diff options
Diffstat (limited to 'src/gl.zig')
| -rw-r--r-- | src/gl.zig | 165 |
1 files changed, 123 insertions, 42 deletions
@@ -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, |
