From 91cb86395bc0e8741e39b5e0b33a4c124bc8079f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 1 Apr 2022 15:38:47 -0700 Subject: [PATCH] opengl: extract into folder --- src/main.zig | 2 +- src/opengl.zig | 141 +---------------------------------------- src/opengl/Program.zig | 60 ++++++++++++++++++ src/opengl/Shader.zig | 55 ++++++++++++++++ src/{ => opengl}/c.zig | 0 src/opengl/errors.zig | 32 ++++++++++ 6 files changed, 151 insertions(+), 139 deletions(-) create mode 100644 src/opengl/Program.zig create mode 100644 src/opengl/Shader.zig rename src/{ => opengl}/c.zig (100%) create mode 100644 src/opengl/errors.zig diff --git a/src/main.zig b/src/main.zig index 351d342ae..12454c6e5 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,7 +1,7 @@ const std = @import("std"); const glfw = @import("glfw"); -const c = @import("c.zig"); const gl = @import("opengl.zig"); +const c = gl.c; pub fn main() !void { try glfw.init(.{}); diff --git a/src/opengl.zig b/src/opengl.zig index f6a3e8e3e..185d3ce77 100644 --- a/src/opengl.zig +++ b/src/opengl.zig @@ -1,138 +1,3 @@ -const std = @import("std"); -const assert = std.debug.assert; -const log = std.log.scoped(.opengl); - -/// This can be used to access the OpenGL headers. -pub const c = @import("c.zig"); - -pub const Error = error{ - InvalidEnum, - InvalidValue, - InvalidOperation, - InvalidFramebufferOperation, - OutOfMemory, - - Unknown, -}; - -/// getError returns the error (if any) from the last OpenGL operation. -pub fn getError() Error!void { - return switch (c.glGetError()) { - c.GL_NO_ERROR => {}, - c.GL_INVALID_ENUM => Error.InvalidEnum, - c.GL_INVALID_VALUE => Error.InvalidValue, - c.GL_INVALID_OPERATION => Error.InvalidOperation, - c.GL_INVALID_FRAMEBUFFER_OPERATION => Error.InvalidFramebufferOperation, - c.GL_OUT_OF_MEMORY => Error.OutOfMemory, - else => Error.Unknown, - }; -} - -/// mustError just calls getError but always results in an error being returned. -/// If getError has no error, then Unknown is returned. -fn mustError() Error!void { - try getError(); - return Error.Unknown; -} - -pub const Shader = struct { - id: c.GLuint, - - pub fn create(typ: c.GLenum) Error!Shader { - const id = c.glCreateShader(typ); - if (id == 0) { - try mustError(); - unreachable; - } - - log.debug("shader created id={}", .{id}); - return Shader{ .id = id }; - } - - /// Set the source and compile a shader. - pub fn setSourceAndCompile(s: Shader, source: [:0]const u8) !void { - c.glShaderSource(s.id, 1, &@ptrCast([*c]const u8, source), null); - c.glCompileShader(s.id); - - // Check if compilation succeeded - var success: c_int = undefined; - c.glGetShaderiv(s.id, c.GL_COMPILE_STATUS, &success); - if (success == c.GL_TRUE) return; - log.err("shader compilation failure id={} message={s}", .{ - s.id, - std.mem.sliceTo(&s.getInfoLog(), 0), - }); - return error.CompileFailed; - } - - /// getInfoLog returns the info log for this shader. This attempts to - /// keep the log fully stack allocated and is therefore limited to a max - /// amount of elements. - // - // NOTE(mitchellh): we can add a dynamic version that uses an allocator - // if we ever need it. - pub fn getInfoLog(s: Shader) [512]u8 { - var msg: [512]u8 = undefined; - c.glGetShaderInfoLog(s.id, msg.len, null, &msg); - return msg; - } - - pub fn destroy(s: Shader) void { - assert(s.id != 0); - c.glDeleteShader(s.id); - log.debug("shader destroyed id={}", .{s.id}); - } -}; - -pub const Program = struct { - id: c.GLuint, - - pub fn create() !Program { - const id = c.glCreateProgram(); - if (id == 0) try mustError(); - - log.debug("program created id={}", .{id}); - return Program{ .id = id }; - } - - pub fn attachShader(p: Program, s: Shader) !void { - c.glAttachShader(p.id, s.id); - try getError(); - } - - pub fn link(p: Program) !void { - c.glLinkProgram(p.id); - - // Check if linking succeeded - var success: c_int = undefined; - c.glGetProgramiv(p.id, c.GL_LINK_STATUS, &success); - if (success == c.GL_TRUE) { - log.debug("program linked id={}", .{p.id}); - return; - } - - log.err("program link failure id={} message={s}", .{ - p.id, - std.mem.sliceTo(&p.getInfoLog(), 0), - }); - return error.CompileFailed; - } - - /// getInfoLog returns the info log for this program. This attempts to - /// keep the log fully stack allocated and is therefore limited to a max - /// amount of elements. - // - // NOTE(mitchellh): we can add a dynamic version that uses an allocator - // if we ever need it. - pub fn getInfoLog(s: Program) [512]u8 { - var msg: [512]u8 = undefined; - c.glGetProgramInfoLog(s.id, msg.len, null, &msg); - return msg; - } - - pub fn destroy(p: Program) void { - assert(p.id != 0); - c.glDeleteProgram(p.id); - log.debug("program destroyed id={}", .{p.id}); - } -}; +pub const c = @import("opengl/c.zig"); +pub const Program = @import("opengl/Program.zig"); +pub const Shader = @import("opengl/Shader.zig"); diff --git a/src/opengl/Program.zig b/src/opengl/Program.zig new file mode 100644 index 000000000..d30a5ccbd --- /dev/null +++ b/src/opengl/Program.zig @@ -0,0 +1,60 @@ +const Program = @This(); + +const std = @import("std"); +const assert = std.debug.assert; +const log = std.log.scoped(.opengl); + +const c = @import("c.zig"); +const Shader = @import("Shader.zig"); +const errors = @import("errors.zig"); + +id: c.GLuint, + +pub fn create() !Program { + const id = c.glCreateProgram(); + if (id == 0) try errors.mustError(); + + log.debug("program created id={}", .{id}); + return Program{ .id = id }; +} + +pub fn attachShader(p: Program, s: Shader) !void { + c.glAttachShader(p.id, s.id); + try errors.getError(); +} + +pub fn link(p: Program) !void { + c.glLinkProgram(p.id); + + // Check if linking succeeded + var success: c_int = undefined; + c.glGetProgramiv(p.id, c.GL_LINK_STATUS, &success); + if (success == c.GL_TRUE) { + log.debug("program linked id={}", .{p.id}); + return; + } + + log.err("program link failure id={} message={s}", .{ + p.id, + std.mem.sliceTo(&p.getInfoLog(), 0), + }); + return error.CompileFailed; +} + +/// getInfoLog returns the info log for this program. This attempts to +/// keep the log fully stack allocated and is therefore limited to a max +/// amount of elements. +// +// NOTE(mitchellh): we can add a dynamic version that uses an allocator +// if we ever need it. +pub fn getInfoLog(s: Program) [512]u8 { + var msg: [512]u8 = undefined; + c.glGetProgramInfoLog(s.id, msg.len, null, &msg); + return msg; +} + +pub fn destroy(p: Program) void { + assert(p.id != 0); + c.glDeleteProgram(p.id); + log.debug("program destroyed id={}", .{p.id}); +} diff --git a/src/opengl/Shader.zig b/src/opengl/Shader.zig new file mode 100644 index 000000000..5809141e1 --- /dev/null +++ b/src/opengl/Shader.zig @@ -0,0 +1,55 @@ +const Shader = @This(); + +const std = @import("std"); +const assert = std.debug.assert; +const log = std.log.scoped(.opengl); + +const c = @import("c.zig"); +const errors = @import("errors.zig"); + +id: c.GLuint, + +pub fn create(typ: c.GLenum) errors.Error!Shader { + const id = c.glCreateShader(typ); + if (id == 0) { + try errors.mustError(); + unreachable; + } + + log.debug("shader created id={}", .{id}); + return Shader{ .id = id }; +} + +/// Set the source and compile a shader. +pub fn setSourceAndCompile(s: Shader, source: [:0]const u8) !void { + c.glShaderSource(s.id, 1, &@ptrCast([*c]const u8, source), null); + c.glCompileShader(s.id); + + // Check if compilation succeeded + var success: c_int = undefined; + c.glGetShaderiv(s.id, c.GL_COMPILE_STATUS, &success); + if (success == c.GL_TRUE) return; + log.err("shader compilation failure id={} message={s}", .{ + s.id, + std.mem.sliceTo(&s.getInfoLog(), 0), + }); + return error.CompileFailed; +} + +/// getInfoLog returns the info log for this shader. This attempts to +/// keep the log fully stack allocated and is therefore limited to a max +/// amount of elements. +// +// NOTE(mitchellh): we can add a dynamic version that uses an allocator +// if we ever need it. +pub fn getInfoLog(s: Shader) [512]u8 { + var msg: [512]u8 = undefined; + c.glGetShaderInfoLog(s.id, msg.len, null, &msg); + return msg; +} + +pub fn destroy(s: Shader) void { + assert(s.id != 0); + c.glDeleteShader(s.id); + log.debug("shader destroyed id={}", .{s.id}); +} diff --git a/src/c.zig b/src/opengl/c.zig similarity index 100% rename from src/c.zig rename to src/opengl/c.zig diff --git a/src/opengl/errors.zig b/src/opengl/errors.zig new file mode 100644 index 000000000..e95c81b7e --- /dev/null +++ b/src/opengl/errors.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const c = @import("c.zig"); + +pub const Error = error{ + InvalidEnum, + InvalidValue, + InvalidOperation, + InvalidFramebufferOperation, + OutOfMemory, + + Unknown, +}; + +/// getError returns the error (if any) from the last OpenGL operation. +pub fn getError() Error!void { + return switch (c.glGetError()) { + c.GL_NO_ERROR => {}, + c.GL_INVALID_ENUM => Error.InvalidEnum, + c.GL_INVALID_VALUE => Error.InvalidValue, + c.GL_INVALID_OPERATION => Error.InvalidOperation, + c.GL_INVALID_FRAMEBUFFER_OPERATION => Error.InvalidFramebufferOperation, + c.GL_OUT_OF_MEMORY => Error.OutOfMemory, + else => Error.Unknown, + }; +} + +/// mustError just calls getError but always results in an error being returned. +/// If getError has no error, then Unknown is returned. +pub fn mustError() Error!void { + try getError(); + return Error.Unknown; +}