diff --git a/.gitmodules b/.gitmodules index c5462a4..37fa83f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "libs/bindbc-common"] path = libs/bindbc-common url = https://github.com/BindBC/bindbc-common +[submodule "libs/gl3n"] + path = libs/gl3n + url = https://github.com/holtrop/gl3n diff --git a/Rsconscript b/Rsconscript index 576eba1..f4225d6 100644 --- a/Rsconscript +++ b/Rsconscript @@ -13,8 +13,10 @@ env "app" do |env| sources = dirs.reduce([]) do |result, dir| result + glob("#{dir}/**/*.{d,c}") end + sources += glob("libs/gl3n/gl3n/**/*.{d,c}") env["D_IMPORT_PATH"] += dirs - env["DFLAGS"] += %w[--d-version=BindBC_Static --d-version=SDL_208] + env["D_IMPORT_PATH"] += ["libs/gl3n"] + env["DFLAGS"] += %w[--d-version=BindBC_Static --d-version=SDL_208 -g] env["LDFLAGS"] += %w[-L-lfreetype -L-lSDL2] env.Program("^/app", sources) end diff --git a/libs/gl3n b/libs/gl3n new file mode 160000 index 0000000..cb23333 --- /dev/null +++ b/libs/gl3n @@ -0,0 +1 @@ +Subproject commit cb233335f50d9cc12f055715b9b42955bf3d379e diff --git a/libs/gltk/gltk/array.d b/libs/gltk/gltk/array.d index d86bf8d..5a6b494 100644 --- a/libs/gltk/gltk/array.d +++ b/libs/gltk/gltk/array.d @@ -34,7 +34,7 @@ class Array /** * Bind array. */ - void bind() const + public void bind() const { glBindVertexArray(m_id); } @@ -42,7 +42,7 @@ class Array /** * Get array ID. */ - @property GLuint id() const + public @property GLuint id() const { return m_id; } diff --git a/libs/gltk/gltk/buffer.d b/libs/gltk/gltk/buffer.d index f88caaa..462c51f 100644 --- a/libs/gltk/gltk/buffer.d +++ b/libs/gltk/gltk/buffer.d @@ -5,21 +5,22 @@ import gl; /** * OpenGL buffer object. */ -class Buffer +class BufferBase(GLenum target = GL_ARRAY_BUFFER) { /** Buffer ID. */ private GLuint m_id; - /** Buffer target. */ - private GLenum m_target; - /** * Construct buffer. * - * @param target - * OpenGL buffer target (e.g. GL_ARRAY_BUFFER, GL_ELEMENT_BUFFER) + * @param data + * Buffer data. + * @param size + * Buffer data size. + * @param usage + * OpenGL buffer usage (default is GL_STATIC_DRAW) */ - this(GLenum target) + this(const(void) * data = null, size_t size, GLenum usage = GL_STATIC_DRAW) { m_id = 0u; glGenBuffers(1, &m_id); @@ -27,7 +28,31 @@ class Buffer { throw new Exception("Failed to allocate an OpenGL buffer"); } - m_target = target; + bind(); + if (data != null) + { + set_buffer_data(data, size, usage); + } + } + + /** + * Construct buffer. + * + * @param data + * Buffer data. + * @param usage + * OpenGL buffer usage (default is GL_STATIC_DRAW) + */ + this(T)(const(T)[] data = null, GLenum usage = GL_STATIC_DRAW) + { + if (data is null) + { + this(null, 0u, usage); + } + else + { + this(data.ptr, data.length * data[0].sizeof, usage); + } } /** @@ -41,15 +66,15 @@ class Buffer /** * Bind buffer. */ - void bind() const + public void bind() const { - glBindBuffer(m_target, m_id); + glBindBuffer(target, m_id); } /** * Get buffer ID. */ - @property GLuint id() const + public @property GLuint id() const { return m_id; } @@ -57,28 +82,43 @@ class Buffer /** * Set buffer data. * - * @param usage - * OpenGL buffer usage (e.g. GL_STATIC_DRAW, ...) - * @param ptr + * @param data * Pointer to buffer data. * @param size * Buffer data size. + * @param usage + * OpenGL buffer usage (default is GL_STATIC_DRAW) */ - void set_buffer_data(GLenum usage, const void * ptr, size_t size) + public void set_buffer_data(const(void) * data, size_t size, GLenum usage = GL_STATIC_DRAW) const { - glNamedBufferData(m_id, size, ptr, usage); + glBufferData(target, size, data, usage); } /** * Set buffer data. * + * @param data + * Buffer data. * @param usage * OpenGL buffer usage (e.g. GL_STATIC_DRAW, ...) - * @param array - * Buffer data. */ - void set_buffer_data(T)(GLenum usage, T[] arr) + public void set_buffer_data(T)(const(T)[] data, GLenum usage = GL_STATIC_DRAW) const { - glNamedBufferData(m_id, arr.length * arr[0].sizeof, arr.ptr, usage); + glBufferData(target, data.length * data[0].sizeof, data.ptr, usage); } } + +/** + * Convenience class alias for a Buffer with a GL_ARRAY_BUFFER target. + */ +alias Buffer = BufferBase!(GL_ARRAY_BUFFER); + +/** + * Convenience class alias for a Buffer with a GL_ELEMENT_ARRAY_BUFFER target. + */ +alias ElementBuffer = BufferBase!(GL_ELEMENT_ARRAY_BUFFER); + +/** + * Convenience class alias for a Buffer with a GL_UNIFORM_BUFFER target. + */ +alias UniformBuffer = BufferBase!(GL_UNIFORM_BUFFER); diff --git a/libs/gltk/gltk/program.d b/libs/gltk/gltk/program.d index f400ecc..0c68fbf 100644 --- a/libs/gltk/gltk/program.d +++ b/libs/gltk/gltk/program.d @@ -20,7 +20,7 @@ import gl; * Attributes are specified as an associative array with attribute names as * keys and attribute locations as values. */ -class Program(string[string] uniforms = [], int[string] attributes = []) +class Program(alias uniforms = [], alias attributes = []) { /** Program ID. */ private GLuint m_id; @@ -151,13 +151,13 @@ class Program(string[string] uniforms = [], int[string] attributes = []) mixin("private GLint m_uniform_" ~ uniform_name ~ ";"); mixin("public void set_" ~ uniform_name ~ "(" ~ uniform_param_decl_list(uniform_type) ~ ") const" ~ "{" ~ - " glProgramUniform" ~ uniform_type ~ "(m_id, m_uniform_" ~ uniform_name ~ ", " ~ (uniform_type_info(uniform_type).v ? "1, " : "") ~ (uniform_type_info(uniform_type).matrix ? "false, " : "") ~ uniform_param_list(uniform_type) ~ ");" ~ + " glProgramUniform" ~ uniform_type ~ "(m_id, m_uniform_" ~ uniform_name ~ ", " ~ (uniform_type_info(uniform_type).v ? "1, " : "") ~ (uniform_type_info(uniform_type).matrix ? "GL_FALSE, " : "") ~ uniform_param_list(uniform_type) ~ ");" ~ "}"); static if (uniform_type_info(uniform_type).v) { mixin("public void set_" ~ uniform_name ~ "(GLsizei count, " ~ uniform_param_decl_list(uniform_type) ~ ") const" ~ "{" ~ - " glProgramUniform" ~ uniform_type ~ "(m_id, m_uniform_" ~ uniform_name ~ ", count, " ~ (uniform_type_info(uniform_type).matrix ? "false, " : "") ~ uniform_param_list(uniform_type) ~ ");" ~ + " glProgramUniform" ~ uniform_type ~ "(m_id, m_uniform_" ~ uniform_name ~ ", count, " ~ (uniform_type_info(uniform_type).matrix ? "GL_FALSE, " : "") ~ uniform_param_list(uniform_type) ~ ");" ~ "}"); } } @@ -346,10 +346,12 @@ class Program(string[string] uniforms = [], int[string] attributes = []) else if (shader_type != 0) { shader_source ~= line; + shader_source ~= "\n"; } else { common_source ~= line; + common_source ~= "\n"; } } diff --git a/libs/gltk/gltk/shader.d b/libs/gltk/gltk/shader.d index 6db2e29..44a53c6 100644 --- a/libs/gltk/gltk/shader.d +++ b/libs/gltk/gltk/shader.d @@ -43,17 +43,20 @@ class Shader string message = "Error compiling "; switch (shader_type) { - case GL_VERTEX_SHADER: - message ~= "vertex"; - break; - case GL_FRAGMENT_SHADER: - message ~= "fragment"; - break; - default: - message ~= "unknown"; - break; + case GL_VERTEX_SHADER: + message ~= "vertex"; + break; + case GL_FRAGMENT_SHADER: + message ~= "fragment"; + break; + default: + message ~= "unknown"; + break; } - message ~= " shader"; + message ~= " shader:\n"; + message ~= "---\n"; + message ~= source; + message ~= "---\n"; GLint log_length; glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &log_length); @@ -61,7 +64,7 @@ class Shader { char[] log = new char[log_length]; glGetShaderInfoLog(m_id, log_length, &log_length, log.ptr); - message ~= "\nShader Log:\n"; + message ~= "Shader Log:\n"; message ~= log; message ~= "\n"; } @@ -80,7 +83,7 @@ class Shader /** * Get shader ID. */ - @property GLuint id() const + public @property GLuint id() const { return m_id; } diff --git a/src/app.d b/src/app.d index 87cb9d2..1cccc59 100644 --- a/src/app.d +++ b/src/app.d @@ -3,10 +3,17 @@ import sdl; import gl; import glad.gl.loader; import gltk; +import gl3n.linalg; enum int WIDTH = 800; enum int HEIGHT = 600; +alias ColorShader = Program!(["view": "Matrix4fv"], ["position": 0, "color": 1]); +ColorShader color_shader; +Array spinny_vao; +GLuint program_id; +mat4 view_matrix; + void init() { glActiveTexture(GL_TEXTURE0); @@ -15,12 +22,65 @@ void init() glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glClearColor (1.0, 0.6, 0.0, 0.0); glViewport(0, 0, WIDTH, HEIGHT); + + spinny_vao = new Array(); + spinny_vao.bind(); + string color_program_src = ` +#version 450 + +uniform mat4 view; + +vertex: + in vec2 position; + in vec4 color; + out vec4 color_i; + void main(void) + { + gl_Position = view * vec4(position, 0.0, 1.0); + color_i = color; + } + +fragment: + in vec4 color_i; + out vec4 frag_color; + void main(void) + { + frag_color = color_i; + }`; + color_shader = new ColorShader(color_program_src); + color_shader.use(); + + float[] vertices = [0.4, 0.4, -0.4, 0.4, -0.4, -0.4, 0.4, -0.4]; + float[] colors = [ + 1.0, 0.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0, + 0.0, 0.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0]; + ushort[] indices = [0, 1, 2, 3]; + Buffer vbo = new Buffer(vertices); + vbo.bind(); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, null); + Buffer cbo = new Buffer(colors); + cbo.bind(); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, null); + ElementBuffer ibo = new ElementBuffer(indices); + ibo.bind(); } void display(SDL_Window * window) { glClear(GL_COLOR_BUFFER_BIT); + color_shader.use(); + spinny_vao.bind(); + view_matrix.make_identity(); + view_matrix.scale(HEIGHT / cast(float)WIDTH, 1.0, 1.0); + view_matrix.rotatez(SDL_GetTicks() / 500.0); + color_shader.set_view(view_matrix.value_ptr); + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, null); + SDL_GL_SwapWindow(window); }