aboutsummaryrefslogtreecommitdiffstats
path: root/src/gl.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/gl.zig')
-rw-r--r--src/gl.zig165
1 files changed, 123 insertions, 42 deletions
diff --git a/src/gl.zig b/src/gl.zig
index 22a2ebe..a24fabf 100644
--- a/src/gl.zig
+++ b/src/gl.zig
@@ -714,27 +714,34 @@ pub const ShaderProgram = struct {
return id;
}
- pub fn create(vert_source: []const u8, frag_source: []const u8) !ShaderProgram {
- var self: ShaderProgram = undefined;
+ fn compileShader(shader_id: c.GLuint, source: []const u8, name: []const u8) !void {
+ const source_ptr: ?[*]const u8 = source.ptr;
+ const source_len = @as(c.GLint, @intCast(source.len));
+ c.glShaderSource(shader_id, 1, &source_ptr, &source_len);
+ c.glCompileShader(shader_id);
- self.vert_id = try initGlShader(vert_source, "vertex", c.GL_VERTEX_SHADER);
- errdefer c.glDeleteShader(self.vert_id);
+ var ok: c.GLint = undefined;
+ c.glGetShaderiv(shader_id, c.GL_COMPILE_STATUS, &ok);
+ if (ok != 0) return;
- self.frag_id = try initGlShader(frag_source, "fragment", c.GL_FRAGMENT_SHADER);
- errdefer c.glDeleteShader(self.frag_id);
+ var error_size: c.GLint = undefined;
+ c.glGetShaderiv(shader_id, c.GL_INFO_LOG_LENGTH, &error_size);
- self.program_id = c.glCreateProgram();
- c.glAttachShader(self.program_id, self.vert_id);
- c.glAttachShader(self.program_id, self.frag_id);
- c.glLinkProgram(self.program_id);
+ const message = try c_allocator.alloc(u8, @as(usize, @intCast(error_size)));
+ c.glGetShaderInfoLog(shader_id, error_size, &error_size, message.ptr);
+ std.debug.print(
+ "Error compiling {s} shader:\n{s}\n",
+ .{ name, @as([*:0]const u8, @ptrCast(message.ptr)) },
+ );
+ return error.CompileError;
+ }
- errdefer c.glDeleteProgram(self.program_id);
- errdefer c.glDetachShader(self.program_id, self.frag_id);
- errdefer c.glDetachShader(self.program_id, self.vert_id);
+ fn linkProgram(self: ShaderProgram) !void {
+ 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;
+ if (ok != 0) return;
var error_size: c.GLint = undefined;
c.glGetProgramiv(self.program_id, c.GL_INFO_LOG_LENGTH, &error_size);
@@ -744,15 +751,113 @@ pub const ShaderProgram = struct {
return error.LinkError;
}
- pub fn destroy(self: *ShaderProgram) void {
- c.glDetachShader(self.program_id, self.frag_id);
- c.glDetachShader(self.program_id, self.vert_id);
+ pub fn create(vert_source: []const u8, frag_source: []const u8) !ShaderProgram {
+ const self: ShaderProgram = .{
+ .program_id = c.glCreateProgram(),
+ .vert_id = c.glCreateShader(c.GL_VERTEX_SHADER),
+ .frag_id = c.glCreateShader(c.GL_FRAGMENT_SHADER),
+ };
+ errdefer self.destroy();
+ c.glAttachShader(self.program_id, self.vert_id);
+ c.glAttachShader(self.program_id, self.frag_id);
+
+ try compileShader(self.vert_id, vert_source, "vertex");
+ try compileShader(self.frag_id, frag_source, "fragment");
+ try self.linkProgram();
+ return self;
+ }
+
+ pub fn destroy(self: *const ShaderProgram) void {
c.glDeleteShader(self.frag_id);
c.glDeleteShader(self.vert_id);
-
c.glDeleteProgram(self.program_id);
}
+
+ pub fn loadString(self: *ShaderProgram, code: []const u8) !void {
+ try compileShader(self.frag_id, code, "fragment");
+ try self.linkProgram();
+ }
+
+ fn escape_dquote(str: []const u8) []const u8 {
+ const state = struct {
+ var buf: [1024]u8 = undefined;
+ };
+
+ const len = std.mem.replacementSize(u8, str, "\"", "\\\"");
+ _ = std.mem.replace(u8, str, "\"", "\\\"", state.buf[0..len]);
+ return state.buf[0..len];
+ }
+
+ // given a file and the directory it is in, resolve references
+ fn readFile(writer: anytype, dir: []const u8, filename: []const u8) !void {
+ const file_dir = try std.fs.path.resolve(c_allocator, &[_][]const u8{
+ dir,
+ std.fs.path.dirname(filename) orelse "",
+ });
+ defer c_allocator.free(file_dir);
+
+ const file_path = try std.fs.path.resolve(c_allocator, &[_][]const u8{ dir, filename });
+ defer c_allocator.free(file_path);
+
+ var file = try std.fs.cwd().openFile(file_path, .{});
+ defer file.close();
+ var reader = file.reader();
+
+ var line_number: u32 = 1;
+ var buf: [1024]u8 = undefined;
+ var wrote_line = false;
+ while (try reader.readUntilDelimiterOrEof(&buf, '\n')) |line| {
+ if (std.mem.startsWith(u8, line, "#pragma ")) {
+ var parts = std.mem.splitScalar(u8, line, ' ');
+ _ = parts.next();
+ const pragma = parts.next().?;
+
+ if (std.mem.eql(u8, pragma, "include")) {
+ var include_path = parts.next().?;
+ if (include_path[0] != '"' or include_path[include_path.len - 1] != '"') {
+ std.debug.print("{s}:{}: Invalid #pragma include\n", .{ file_path, line_number });
+ std.debug.print("{s}:{}: {s}\n", .{ file_path, line_number, line });
+ continue;
+ }
+ include_path = include_path[1 .. include_path.len - 1];
+
+ readFile(writer, file_dir, include_path) catch unreachable;
+ _ = try writer.print("#line {d} \"{s}\"\n", .{ line_number, escape_dquote(filename) });
+
+ continue;
+ } else {
+ std.debug.print("{s}:{}: Unknown #pragma directive '{s}'\n", .{ file_path, line_number, pragma });
+ std.debug.print("{s}:{}: {s}\n", .{ file_path, line_number, line });
+ }
+ }
+
+ if (!std.mem.startsWith(u8, line, "#version") and !wrote_line) {
+ _ = try writer.print("#line {d} \"{s}\"\n", .{ line_number - 1, escape_dquote(filename) });
+ wrote_line = true;
+ }
+
+ _ = try writer.write(line);
+ _ = try writer.write("\n");
+
+ line_number += 1;
+ }
+ }
+
+ pub fn loadFile(self: *ShaderProgram, filename: []const u8, size: u64) !void {
+ var buffer = try std.ArrayList(u8).initCapacity(c_allocator, @as(usize, @intCast(size)) + 150);
+ defer buffer.deinit();
+
+ const writer = buffer.writer();
+ _ = try writer.write(
+ \\#version 330 core
+ \\#extension GL_ARB_shading_language_include : require
+ \\
+ );
+ try readFile(writer, "", filename);
+
+ try self.loadString(buffer.items);
+ }
};
pub const UniformCache = struct {
@@ -821,30 +926,6 @@ pub const UniformCache = struct {
}
};
-fn initGlShader(source: []const u8, name: []const u8, kind: c.GLenum) !c.GLuint {
- const shader_id = c.glCreateShader(kind);
- errdefer c.glDeleteShader(shader_id);
- const source_ptr: ?[*]const u8 = source.ptr;
- const source_len = @as(c.GLint, @intCast(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, @as(usize, @intCast(error_size)));
- c.glGetShaderInfoLog(shader_id, error_size, &error_size, message.ptr);
- std.debug.print(
- "Error compiling {s} shader:\n{s}\n",
- .{ name, @as([*:0]const u8, @ptrCast(message.ptr)) },
- );
- return error.CompileError;
-}
-
pub const FramebufferObject = struct {
buffer_id: c.GLuint,
texture_id: c.GLuint,