diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-01-23 14:00:16 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-01-23 15:06:29 +0000 |
| commit | 866fccb01e40ab11add47511c922ec2dd8f0454e (patch) | |
| tree | 47cde0299aa8225860fc2bfee52b8abde329fad5 /src/gl.zig | |
| parent | initial commit (diff) | |
| download | glsl-view-866fccb01e40ab11add47511c922ec2dd8f0454e.tar.gz glsl-view-866fccb01e40ab11add47511c922ec2dd8f0454e.zip | |
Code reorganisation
Diffstat (limited to 'src/gl.zig')
| -rw-r--r-- | src/gl.zig | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/src/gl.zig b/src/gl.zig new file mode 100644 index 0000000..c974cea --- /dev/null +++ b/src/gl.zig @@ -0,0 +1,255 @@ +const c_allocator = @import("std").heap.c_allocator; +const panic = @import("std").debug.panic; +const c = @import("c.zig"); + +pub const ShaderProgram = struct { + program_id: c.GLuint, + vertex_id: c.GLuint, + fragment_id: c.GLuint, + maybe_geometry_id: ?c.GLuint, + + pub fn bind(self: ShaderProgram) void { + c.glUseProgram(self.program_id); + } + + pub fn attribLocation(self: ShaderProgram, name: [*]const u8) c.GLint { + const id = c.glGetAttribLocation(self.program_id, name); + if (id == -1) { + panic("invalid attrib: {}\n", .{name}); + } + return id; + } + + pub fn uniformLocation(self: ShaderProgram, name: [*]const u8) c.GLint { + const id = c.glGetUniformLocation(self.program_id, name); + if (id == -1) { + panic("invalid uniform: {}\n", .{name}); + } + return id; + } + + pub fn setUniformInt(self: ShaderProgram, uniform_id: c.GLint, value: c_int) void { + c.glUniform1i(uniform_id, value); + } + + pub fn setUniformFloat(self: ShaderProgram, uniform_id: c.GLint, value: f32) void { + c.glUniform1f(uniform_id, value); + } + + pub fn setUniformVec2(self: ShaderProgram, uniform_id: c.GLint, value: [2]f32) void { + c.glUniform3fv(uniform_id, 1, value.ptr); + } + + pub fn setUniformVec3(self: ShaderProgram, uniform_id: c.GLint, value: [3]f32) void { + c.glUniform3fv(uniform_id, 1, value.ptr); + } + + pub fn setUniformVec4(self: ShaderProgram, uniform_id: c.GLint, value: [4]f32) void { + c.glUniform4fv(uniform_id, 1, value.ptr); + } + + pub fn setUniformMat4x4(self: ShaderProgram, uniform_id: c.GLint, value: [4][4]f32) void { + c.glUniformMatrix4fv(uniform_id, 1, c.GL_FALSE, &value[0][0]); + } + + pub fn create( + vertex_source: []const u8, + frag_source: []const u8, + maybe_geometry_source: ?[]u8, + ) !ShaderProgram { + var self: ShaderProgram = undefined; + self.vertex_id = try initGlShader(vertex_source, "vertex", c.GL_VERTEX_SHADER); + self.fragment_id = try initGlShader(frag_source, "fragment", c.GL_FRAGMENT_SHADER); + self.maybe_geometry_id = if (maybe_geometry_source) |geo_source| + try initGlShader(geo_source, "geometry", c.GL_GEOMETRY_SHADER) + else + null; + + self.program_id = c.glCreateProgram(); + c.glAttachShader(self.program_id, self.vertex_id); + c.glAttachShader(self.program_id, self.fragment_id); + if (self.maybe_geometry_id) |geo_id| { + c.glAttachShader(self.program_id, geo_id); + } + c.glLinkProgram(self.program_id); + + var ok: c.GLint = undefined; + c.glGetProgramiv(self.program_id, c.GL_LINK_STATUS, &ok); + if (ok != 0) return self; + + var error_size: c.GLint = undefined; + c.glGetProgramiv(self.program_id, c.GL_INFO_LOG_LENGTH, &error_size); + const message = try c_allocator.alloc(u8, @intCast(usize, error_size)); + c.glGetProgramInfoLog(self.program_id, error_size, &error_size, message.ptr); + panic("Error linking shader program: {s}\n", .{ @ptrCast([*:0]const u8, message.ptr) }); + } + + pub fn destroy(self: *ShaderProgram) void { + if (self.maybe_geometry_id) |geo_id| { + c.glDetachShader(self.program_id, geo_id); + } + c.glDetachShader(self.program_id, self.fragment_id); + c.glDetachShader(self.program_id, self.vertex_id); + + if (self.maybe_geometry_id) |geo_id| { + c.glDeleteShader(geo_id); + } + c.glDeleteShader(self.fragment_id); + c.glDeleteShader(self.vertex_id); + + c.glDeleteProgram(self.program_id); + } +}; + +fn initGlShader(source: []const u8, name: []const u8, kind: c.GLenum) !c.GLuint { + const shader_id = c.glCreateShader(kind); + const source_ptr: ?[*]const u8 = source.ptr; + const source_len = @intCast(c.GLint, source.len); + c.glShaderSource(shader_id, 1, &source_ptr, &source_len); + c.glCompileShader(shader_id); + + var ok: c.GLint = undefined; + c.glGetShaderiv(shader_id, c.GL_COMPILE_STATUS, &ok); + if (ok != 0) return shader_id; + + var error_size: c.GLint = undefined; + c.glGetShaderiv(shader_id, c.GL_INFO_LOG_LENGTH, &error_size); + + const message = try c_allocator.alloc(u8, @intCast(usize, error_size)); + c.glGetShaderInfoLog(shader_id, error_size, &error_size, message.ptr); + panic("Error compiling {s} shader:\n{s}\n", .{ name, @ptrCast([*:0]const u8, message.ptr) }); +} + +pub const FramebufferObject = struct { + buffer_id: c.GLuint, + texture_id: c.GLuint, + + pub fn bind(self: FramebufferObject) void { + c.glBindFramebuffer(c.GL_FRAMEBUFFER, self.buffer_id); + } + + pub fn unbind(self: FramebufferObject) void { + c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0); + } + + pub fn create(width: i32, height: i32) !FramebufferObject { + var self: FramebufferObject = undefined; + c.glGenFramebuffers(1, &self.buffer_id); + c.glBindFramebuffer(c.GL_FRAMEBUFFER, self.buffer_id); + + c.glGenTextures(1, &self.texture_id); + c.glBindTexture(c.GL_TEXTURE_2D, self.texture_id); + c.glTexImage2D(c.GL_TEXTURE_2D, 0, c.GL_RGBA, width, height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, null); + c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_LINEAR); + c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_LINEAR); + c.glBindTexture(c.GL_TEXTURE_2D, 0); + + c.glFramebufferTexture2D(c.GL_FRAMEBUFFER, c.GL_COLOR_ATTACHMENT0, c.GL_TEXTURE_2D, self.texture_id, 0); + + + if (c.glCheckFramebufferStatus(c.GL_FRAMEBUFFER) != c.GL_FRAMEBUFFER_COMPLETE) + return error.FBONotComplete; + + c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0); + return self; + } + + pub fn destroy(self: *FramebufferObject) void { + c.glDeleteFramebuffers(1, &self.*.buffer_id); + c.glDeleteTextures(1, &self.*.texture_id); + } +}; + +pub const VertexObject = struct { + array_id: c.GLuint, + buffer_id: c.GLuint, + vertex_size: i32, + vertex_count: i32, + + pub fn bind(self: VertexObject, attrib: u32) void { + c.glBindBuffer(c.GL_ARRAY_BUFFER, self.buffer_id); + c.glEnableVertexAttribArray(attrib); + c.glVertexAttribPointer(attrib, self.vertex_size, c.GL_FLOAT, c.GL_FALSE, 0, null); + } + + pub fn draw(self: VertexObject) void { + c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, self.vertex_count); + } + + pub fn create(comptime T: type, vertices: []const T, vertex_size: i32) VertexObject { + var self: VertexObject = undefined; + + self.vertex_size = vertex_size; + self.vertex_count = @intCast(i32, vertices.len); + + c.glGenVertexArrays(1, &self.array_id); + c.glBindVertexArray(self.array_id); + + c.glGenBuffers(1, &self.buffer_id); + c.glBindBuffer(c.GL_ARRAY_BUFFER, self.buffer_id); + c.glBufferData(c.GL_ARRAY_BUFFER, + @intCast(c_long, @sizeOf(T) * vertices.len), + @ptrCast(*const c_void, &vertices[0]), + c.GL_STATIC_DRAW); + + return self; + } + + pub fn destroy(self: *VertexObject) void { + defer c.glDeleteBuffers(1, &self.*.buffer_id); + defer c.glDeleteVertexArrays(1, &self.*.array_id); + } +}; + +pub const Constants = struct { + textureShader: ShaderProgram, + normalizedQuad: VertexObject, + main_window: *c.GLFWwindow, + + pub fn create(main_window: *c.GLFWwindow) !Constants { + var self: Constants = undefined; + + c.glfwMakeContextCurrent(main_window); + self.main_window = main_window; + + self.textureShader = try ShaderProgram.create( + \\#version 330 core + \\ + \\layout(location = 0) in vec2 position; + \\out vec2 uv; + \\ + \\void main() { + \\ uv = position / 2.0 + 0.5; + \\ gl_Position = vec4(position, 0, 1); + \\} + , + \\#version 330 core + \\ + \\in vec2 uv; + \\out vec4 color; + \\ + \\uniform sampler2D colorTexture; + \\ + \\void main(){ + \\ color = texture(colorTexture, uv); + \\} + , + null + ); + + const vertices = [_]c.GLfloat{ + -1.0, -1.0, + -1.0, 1.0, + 1.0, -1.0, + 1.0, 1.0, + }; + self.normalizedQuad = VertexObject.create(f32, vertices[0..], 2); + + return self; + } + + pub fn destroy(self: *Constants) void { + self.normalizedQuad.destroy(); + self.textureShader.destroy(); + } +}; |
