diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-01-26 19:49:25 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-01-26 19:49:25 +0000 |
| commit | 885a8652cb8a433a18811d90048d11c1ec67b60e (patch) | |
| tree | 52b845a825c91ec878983eb1078b4bd48f27ec73 /src | |
| parent | remove offset default uniform (diff) | |
| download | glsl-view-885a8652cb8a433a18811d90048d11c1ec67b60e.tar.gz glsl-view-885a8652cb8a433a18811d90048d11c1ec67b60e.zip | |
break OSC in favor of uniform caching
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.zig | 4 | ||||
| -rw-r--r-- | src/control.zig | 61 | ||||
| -rw-r--r-- | src/debug_gl.zig | 22 | ||||
| -rw-r--r-- | src/gl.zig | 401 | ||||
| -rw-r--r-- | src/main.zig | 22 | ||||
| -rw-r--r-- | src/output.zig | 49 |
6 files changed, 472 insertions, 87 deletions
diff --git a/src/config.zig b/src/config.zig index e2af1e9..ad4a181 100644 --- a/src/config.zig +++ b/src/config.zig @@ -28,7 +28,7 @@ pub const OSCConfig = union(enum) { tcp, unix, }; - + Manual: struct { protocol: Protocol = Protocol.udp, port: u16 = 9000, @@ -60,7 +60,7 @@ pub const Config = struct { const file = try fs.cwd().openFile(filename, .{}); var buffer: [1024]u8 = undefined; const len: usize = try file.read(buffer[0..]); - c.yaml_parser_set_input_string(&parser, &buffer[0], len); + c.yaml_parser_set_input_string(&parser, buffer[0..].ptr, len); var config: Config = .{ .width = 1920, diff --git a/src/control.zig b/src/control.zig index 3d36d8f..cec6f80 100644 --- a/src/control.zig +++ b/src/control.zig @@ -22,13 +22,13 @@ pub const ControlServer = struct { .unix => c.LO_UNIX, else => unreachable, }; - - std.debug.warn("listening for OSC messages on {} port {}\n", .{conf.protocol, conf.port}); - self.server = c.lo_server_new_with_proto(&port[0], proto, handle_error); + + std.debug.warn("listening for OSC messages on {} port {}\n", .{ conf.protocol, conf.port }); + self.server = c.lo_server_new_with_proto(port[0..].ptr, proto, handle_error); }, .URL => |url| { std.debug.warn("listening for OSC messages at {s}\n", .{url}); - self.server = c.lo_server_new_from_url(&url[0], handle_error); + self.server = c.lo_server_new_from_url(url[0..].ptr, handle_error); }, else => unreachable, } @@ -58,32 +58,37 @@ pub const ControlServer = struct { const path = _path[0..c.strlen(_path)]; const types = _types[0..@intCast(u32, argc)]; - if (std.mem.startsWith(u8, path, param_prefix)) { - const param_name = path[param_prefix.len..]; - - const uniform = self.shader.uniformLocation(@ptrCast([*]const u8, param_name.ptr)) catch { - std.debug.warn("param {s} doesn't exist\n", .{param_name}); - return 0; - }; - - if (argc == 0) { - std.debug.warn("param get: {s}\n", .{param_name}); - return 0; + if (std.mem.startsWith(u8, path, "/param/")) { + if (!std.mem.endsWith(u8, path, "/set")) { + std.debug.warn("unhandled OSC message {s} ({s})\n", .{ path, types }); + return 1; } - if (std.mem.eql(u8, types, "f")) { - self.shader.setUniform1f(uniform, argv[0].*.f); - } else if (std.mem.eql(u8, types, "ff")) { - self.shader.setUniform2f(uniform, argv[0].*.f, argv[1].*.f); - } else if (std.mem.eql(u8, types, "fff")) { - self.shader.setUniform3f(uniform, argv[0].*.f, argv[1].*.f, argv[2].*.f); - } else if (std.mem.eql(u8, types, "ffff")) { - self.shader.setUniform4f(uniform, argv[0].*.f, argv[1].*.f, argv[2].*.f, argv[3].*.f); - } else if (std.mem.eql(u8, types, "i")) { - self.shader.setUniform1i(uniform, argv[0].*.i); - } else { - std.debug.warn("unsupported types: {s}\n", .{types}); - } + const name_slice = path["/param/".len .. path.len - "/set".len]; + // const uniform = self.shader.uniformLocation(name) catch { + // std.debug.warn("param {s} doesn't exist\n", .{uniform_name}); + // return 0; + // }; + + // if (std.mem.eql(u8, types, "f")) { + // self.shader.setUniform1f(uniform, argv[0].*.f); + // } else if (std.mem.eql(u8, types, "ff")) { + // self.shader.setUniform2f(uniform, argv[0].*.f, argv[1].*.f); + // } else if (std.mem.eql(u8, types, "fff")) { + // self.shader.setUniform3f(uniform, argv[0].*.f, argv[1].*.f, argv[2].*.f); + // } else if (std.mem.eql(u8, types, "ffff")) { + // self.shader.setUniform4f(uniform, argv[0].*.f, argv[1].*.f, argv[2].*.f, argv[3].*.f); + // } else if (std.mem.eql(u8, types, "i")) { + // self.shader.setUniform1i(uniform, argv[0].*.i); + // } else if (std.mem.eql(u8, types, "ii")) { + // self.shader.setUniform2i(uniform, argv[0].*.i, argv[1].*.i); + // } else if (std.mem.eql(u8, types, "iii")) { + // self.shader.setUniform3i(uniform, argv[0].*.i, argv[1].*.i, argv[2].*.i); + // } else if (std.mem.eql(u8, types, "iiii")) { + // self.shader.setUniform4i(uniform, argv[0].*.i, argv[1].*.i, argv[2].*.i, argv[3].*.i); + // } else { + // std.debug.warn("unsupported types: {s}\n", .{types}); + // } return 0; } diff --git a/src/debug_gl.zig b/src/debug_gl.zig index 2fdcda0..ebb552f 100644 --- a/src/debug_gl.zig +++ b/src/debug_gl.zig @@ -6,11 +6,27 @@ const builtin = @import("builtin"); pub const is_on = if (builtin.mode == builtin.Mode.ReleaseFast) c.GL_FALSE else c.GL_TRUE; +fn glDebugMessage(source: c.GLenum, typ: c.GLenum, id: c.GLuint, severity: c.GLenum, length: c.GLsizei, _message: [*c]const u8, user: ?*const c_void) callconv(.C) void { + const message = _message[0..@intCast(usize, length)]; + std.debug.warn("GL Callback [{}] {} / {}: {s}\n", .{ source, typ, severity, message }); +} + +pub fn init() void { + if (is_on == c.GL_TRUE) { + c.glEnable(c.GL_DEBUG_OUTPUT); + c.glDebugMessageCallback(glDebugMessage, null); + } +} + pub fn assertNoError() void { - if (builtin.mode != builtin.Mode.ReleaseFast) { - const err = c.glGetError(); - if (err != c.GL_NO_ERROR) { + if (is_on == c.GL_TRUE) { + var err = c.glGetError(); + while (err != c.GL_NO_ERROR) : (err = c.glGetError()) { panic("GL error: {}\n", .{err}); + } else { + return; } + + panic("GL Errors encountered.\n", .{err}); } } @@ -2,6 +2,292 @@ const std = @import("std"); const c_allocator = @import("std").heap.c_allocator; const panic = @import("std").debug.panic; const c = @import("c.zig"); +const cfg = @import("config.zig"); + +const UniformType = enum(c.GLint) { + FLOAT = c.GL_FLOAT, + FLOAT_VEC2 = c.GL_FLOAT_VEC2, + FLOAT_VEC3 = c.GL_FLOAT_VEC3, + FLOAT_VEC4 = c.GL_FLOAT_VEC4, + DOUBLE = c.GL_DOUBLE, + DOUBLE_VEC2 = c.GL_DOUBLE_VEC2, + DOUBLE_VEC3 = c.GL_DOUBLE_VEC3, + DOUBLE_VEC4 = c.GL_DOUBLE_VEC4, + INT = c.GL_INT, + INT_VEC2 = c.GL_INT_VEC2, + INT_VEC3 = c.GL_INT_VEC3, + INT_VEC4 = c.GL_INT_VEC4, + UNSIGNED_INT = c.GL_UNSIGNED_INT, + UNSIGNED_INT_VEC2 = c.GL_UNSIGNED_INT_VEC2, + UNSIGNED_INT_VEC3 = c.GL_UNSIGNED_INT_VEC3, + UNSIGNED_INT_VEC4 = c.GL_UNSIGNED_INT_VEC4, + BOOL = c.GL_BOOL, + BOOL_VEC2 = c.GL_BOOL_VEC2, + BOOL_VEC3 = c.GL_BOOL_VEC3, + BOOL_VEC4 = c.GL_BOOL_VEC4, + FLOAT_MAT2 = c.GL_FLOAT_MAT2, + FLOAT_MAT3 = c.GL_FLOAT_MAT3, + FLOAT_MAT4 = c.GL_FLOAT_MAT4, + FLOAT_MAT2x3 = c.GL_FLOAT_MAT2x3, + FLOAT_MAT2x4 = c.GL_FLOAT_MAT2x4, + FLOAT_MAT3x2 = c.GL_FLOAT_MAT3x2, + FLOAT_MAT3x4 = c.GL_FLOAT_MAT3x4, + FLOAT_MAT4x2 = c.GL_FLOAT_MAT4x2, + FLOAT_MAT4x3 = c.GL_FLOAT_MAT4x3, + DOUBLE_MAT2 = c.GL_DOUBLE_MAT2, + DOUBLE_MAT3 = c.GL_DOUBLE_MAT3, + DOUBLE_MAT4 = c.GL_DOUBLE_MAT4, + DOUBLE_MAT2x3 = c.GL_DOUBLE_MAT2x3, + DOUBLE_MAT2x4 = c.GL_DOUBLE_MAT2x4, + DOUBLE_MAT3x2 = c.GL_DOUBLE_MAT3x2, + DOUBLE_MAT3x4 = c.GL_DOUBLE_MAT3x4, + DOUBLE_MAT4x2 = c.GL_DOUBLE_MAT4x2, + DOUBLE_MAT4x3 = c.GL_DOUBLE_MAT4x3, + SAMPLER_1D = c.GL_SAMPLER_1D, + SAMPLER_2D = c.GL_SAMPLER_2D, + SAMPLER_3D = c.GL_SAMPLER_3D, + SAMPLER_CUBE = c.GL_SAMPLER_CUBE, + SAMPLER_1D_SHADOW = c.GL_SAMPLER_1D_SHADOW, + SAMPLER_2D_SHADOW = c.GL_SAMPLER_2D_SHADOW, + SAMPLER_1D_ARRAY = c.GL_SAMPLER_1D_ARRAY, + SAMPLER_2D_ARRAY = c.GL_SAMPLER_2D_ARRAY, + SAMPLER_1D_ARRAY_SHADOW = c.GL_SAMPLER_1D_ARRAY_SHADOW, + SAMPLER_2D_ARRAY_SHADOW = c.GL_SAMPLER_2D_ARRAY_SHADOW, + SAMPLER_2D_MULTISAMPLE = c.GL_SAMPLER_2D_MULTISAMPLE, + SAMPLER_2D_MULTISAMPLE_ARRAY = c.GL_SAMPLER_2D_MULTISAMPLE_ARRAY, + SAMPLER_CUBE_SHADOW = c.GL_SAMPLER_CUBE_SHADOW, + SAMPLER_BUFFER = c.GL_SAMPLER_BUFFER, + SAMPLER_2D_RECT = c.GL_SAMPLER_2D_RECT, + SAMPLER_2D_RECT_SHADOW = c.GL_SAMPLER_2D_RECT_SHADOW, + INT_SAMPLER_1D = c.GL_INT_SAMPLER_1D, + INT_SAMPLER_2D = c.GL_INT_SAMPLER_2D, + INT_SAMPLER_3D = c.GL_INT_SAMPLER_3D, + INT_SAMPLER_CUBE = c.GL_INT_SAMPLER_CUBE, + INT_SAMPLER_1D_ARRAY = c.GL_INT_SAMPLER_1D_ARRAY, + INT_SAMPLER_2D_ARRAY = c.GL_INT_SAMPLER_2D_ARRAY, + INT_SAMPLER_2D_MULTISAMPLE = c.GL_INT_SAMPLER_2D_MULTISAMPLE, + INT_SAMPLER_2D_MULTISAMPLE_ARRAY = c.GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, + INT_SAMPLER_BUFFER = c.GL_INT_SAMPLER_BUFFER, + INT_SAMPLER_2D_RECT = c.GL_INT_SAMPLER_2D_RECT, + UNSIGNED_INT_SAMPLER_1D = c.GL_UNSIGNED_INT_SAMPLER_1D, + UNSIGNED_INT_SAMPLER_2D = c.GL_UNSIGNED_INT_SAMPLER_2D, + UNSIGNED_INT_SAMPLER_3D = c.GL_UNSIGNED_INT_SAMPLER_3D, + UNSIGNED_INT_SAMPLER_CUBE = c.GL_UNSIGNED_INT_SAMPLER_CUBE, + UNSIGNED_INT_SAMPLER_1D_ARRAY = c.GL_UNSIGNED_INT_SAMPLER_1D_ARRAY, + UNSIGNED_INT_SAMPLER_2D_ARRAY = c.GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, + UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = c.GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, + UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = c.GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, + UNSIGNED_INT_SAMPLER_BUFFER = c.GL_UNSIGNED_INT_SAMPLER_BUFFER, + UNSIGNED_INT_SAMPLER_2D_RECT = c.GL_UNSIGNED_INT_SAMPLER_2D_RECT, +}; + +const UniformValue = union(UniformType) { + FLOAT: f32, + FLOAT_VEC2: [2]f32, + FLOAT_VEC3: [3]f32, + FLOAT_VEC4: [4]f32, + DOUBLE: f64, + DOUBLE_VEC2: [2]f64, + DOUBLE_VEC3: [3]f64, + DOUBLE_VEC4: [4]f64, + INT: c_int, // i32 but bug + INT_VEC2: [2]c_int, + INT_VEC3: [3]c_int, + INT_VEC4: [4]c_int, + UNSIGNED_INT: c_uint, + UNSIGNED_INT_VEC2: [2]c_uint, + UNSIGNED_INT_VEC3: [3]c_uint, + UNSIGNED_INT_VEC4: [4]c_uint, + BOOL: c_uint, + BOOL_VEC2: [2]c_uint, + BOOL_VEC3: [3]c_uint, + BOOL_VEC4: [4]c_uint, + FLOAT_MAT2: [2 * 2]f32, + FLOAT_MAT3: [3 * 3]f32, + FLOAT_MAT4: [4 * 4]f32, + FLOAT_MAT2x3: [2 * 3]f32, + FLOAT_MAT2x4: [2 * 4]f32, + FLOAT_MAT3x2: [3 * 2]f32, + FLOAT_MAT3x4: [3 * 4]f32, + FLOAT_MAT4x2: [4 * 2]f32, + FLOAT_MAT4x3: [4 * 3]f32, + DOUBLE_MAT2: [2 * 2]f64, + DOUBLE_MAT3: [3 * 3]f64, + DOUBLE_MAT4: [4 * 4]f64, + DOUBLE_MAT2x3: [2 * 3]f64, + DOUBLE_MAT2x4: [2 * 4]f64, + DOUBLE_MAT3x2: [3 * 2]f64, + DOUBLE_MAT3x4: [3 * 4]f64, + DOUBLE_MAT4x2: [4 * 2]f64, + DOUBLE_MAT4x3: [4 * 3]f64, + SAMPLER_1D: c_int, + SAMPLER_2D: c_int, + SAMPLER_3D: c_int, + SAMPLER_CUBE: c_int, + SAMPLER_1D_SHADOW: c_int, + SAMPLER_2D_SHADOW: c_int, + SAMPLER_1D_ARRAY: c_int, + SAMPLER_2D_ARRAY: c_int, + SAMPLER_1D_ARRAY_SHADOW: c_int, + SAMPLER_2D_ARRAY_SHADOW: c_int, + SAMPLER_2D_MULTISAMPLE: c_int, + SAMPLER_2D_MULTISAMPLE_ARRAY: c_int, + SAMPLER_CUBE_SHADOW: c_int, + SAMPLER_BUFFER: c_int, + SAMPLER_2D_RECT: c_int, + SAMPLER_2D_RECT_SHADOW: c_int, + INT_SAMPLER_1D: c_int, + INT_SAMPLER_2D: c_int, + INT_SAMPLER_3D: c_int, + INT_SAMPLER_CUBE: c_int, + INT_SAMPLER_1D_ARRAY: c_int, + INT_SAMPLER_2D_ARRAY: c_int, + INT_SAMPLER_2D_MULTISAMPLE: c_int, + INT_SAMPLER_2D_MULTISAMPLE_ARRAY: c_int, + INT_SAMPLER_BUFFER: c_int, + INT_SAMPLER_2D_RECT: c_int, + UNSIGNED_INT_SAMPLER_1D: c_int, + UNSIGNED_INT_SAMPLER_2D: c_int, + UNSIGNED_INT_SAMPLER_3D: c_int, + UNSIGNED_INT_SAMPLER_CUBE: c_int, + UNSIGNED_INT_SAMPLER_1D_ARRAY: c_int, + UNSIGNED_INT_SAMPLER_2D_ARRAY: c_int, + UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: c_int, + UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: c_int, + UNSIGNED_INT_SAMPLER_BUFFER: c_int, + UNSIGNED_INT_SAMPLER_2D_RECT: c_int, + + pub fn init(utype: UniformType) UniformValue { + inline for (@typeInfo(UniformType).Enum.fields) |field| { + if (@intToEnum(UniformType, field.value) == utype) + return @unionInit(UniformValue, field.name, undefined); + } + + unreachable; + } +}; + +const CachedUniform = struct { + value: UniformValue, + location: c.GLint, + + pub fn init(shader: ShaderProgram, name: [*]const u8) !CachedUniform { + var index: c.GLuint = undefined; + + c.glGetUniformIndices(shader.program_id, 1, &name, &index); + if (index == c.GL_INVALID_INDEX) + return error.invalidUniform; + + var utype: c.GLint = undefined; + c.glGetActiveUniformsiv(shader.program_id, 1, &index, c.GL_UNIFORM_TYPE, &utype); + + var self = CachedUniform{ + .value = UniformValue.init(@intToEnum(UniformType, utype)), + .location = try shader.uniformLocation(name), + }; + + self.getShaderValue(shader); + return self; + } + + // zig fmt: off + pub fn setShaderValue(self: *const CachedUniform, shader: ShaderProgram) void { + const program = shader.program_id; + const location = self.location; + + switch (self.value) { + .FLOAT => |*value| c.glProgramUniform1fv(program, location, 1, value), + .FLOAT_VEC2 => |*value| c.glProgramUniform2fv(program, location, 1, value), + .FLOAT_VEC3 => |*value| c.glProgramUniform3fv(program, location, 1, value), + .FLOAT_VEC4 => |*value| c.glProgramUniform4fv(program, location, 1, value), + .DOUBLE => |*value| c.glProgramUniform1dv(program, location, 1, value), + .DOUBLE_VEC2 => |*value| c.glProgramUniform1dv(program, location, 1, value), + .DOUBLE_VEC3 => |*value| c.glProgramUniform2dv(program, location, 1, value), + .DOUBLE_VEC4 => |*value| c.glProgramUniform3dv(program, location, 1, value), + .INT => |*value| c.glProgramUniform1iv(program, location, 1, value), + .INT_VEC2 => |*value| c.glProgramUniform2iv(program, location, 1, value), + .INT_VEC3 => |*value| c.glProgramUniform3iv(program, location, 1, value), + .INT_VEC4 => |*value| c.glProgramUniform4iv(program, location, 1, value), + .UNSIGNED_INT => |*value| c.glProgramUniform1uiv(program, location, 1, value), + .UNSIGNED_INT_VEC2 => |*value| c.glProgramUniform2uiv(program, location, 1, value), + .UNSIGNED_INT_VEC3 => |*value| c.glProgramUniform3uiv(program, location, 1, value), + .UNSIGNED_INT_VEC4 => |*value| c.glProgramUniform4uiv(program, location, 1, value), + .BOOL => |*value| c.glProgramUniform1uiv(program, location, 1, value), + .BOOL_VEC2 => |*value| c.glProgramUniform2uiv(program, location, 1, value), + .BOOL_VEC3 => |*value| c.glProgramUniform3uiv(program, location, 1, value), + .BOOL_VEC4 => |*value| c.glProgramUniform4uiv(program, location, 1, value), + .FLOAT_MAT2 => |*value| c.glProgramUniformMatrix2fv(program, location, 1, c.GL_FALSE, value), + .FLOAT_MAT3 => |*value| c.glProgramUniformMatrix3fv(program, location, 1, c.GL_FALSE, value), + .FLOAT_MAT4 => |*value| c.glProgramUniformMatrix4fv(program, location, 1, c.GL_FALSE, value), + .FLOAT_MAT2x3 => |*value| c.glProgramUniformMatrix2x3fv(program, location, 1, c.GL_FALSE, value), + .FLOAT_MAT2x4 => |*value| c.glProgramUniformMatrix2x4fv(program, location, 1, c.GL_FALSE, value), + .FLOAT_MAT3x2 => |*value| c.glProgramUniformMatrix3x2fv(program, location, 1, c.GL_FALSE, value), + .FLOAT_MAT3x4 => |*value| c.glProgramUniformMatrix3x4fv(program, location, 1, c.GL_FALSE, value), + .FLOAT_MAT4x2 => |*value| c.glProgramUniformMatrix4x2fv(program, location, 1, c.GL_FALSE, value), + .FLOAT_MAT4x3 => |*value| c.glProgramUniformMatrix4x3fv(program, location, 1, c.GL_FALSE, value), + .DOUBLE_MAT2 => |*value| c.glProgramUniformMatrix2dv(program, location, 1, c.GL_FALSE, value), + .DOUBLE_MAT3 => |*value| c.glProgramUniformMatrix3dv(program, location, 1, c.GL_FALSE, value), + .DOUBLE_MAT4 => |*value| c.glProgramUniformMatrix4dv(program, location, 1, c.GL_FALSE, value), + .DOUBLE_MAT2x3 => |*value| c.glProgramUniformMatrix2x3dv(program, location, 1, c.GL_FALSE, value), + .DOUBLE_MAT2x4 => |*value| c.glProgramUniformMatrix2x4dv(program, location, 1, c.GL_FALSE, value), + .DOUBLE_MAT3x2 => |*value| c.glProgramUniformMatrix3x2dv(program, location, 1, c.GL_FALSE, value), + .DOUBLE_MAT3x4 => |*value| c.glProgramUniformMatrix3x4dv(program, location, 1, c.GL_FALSE, value), + .DOUBLE_MAT4x2 => |*value| c.glProgramUniformMatrix4x2dv(program, location, 1, c.GL_FALSE, value), + .DOUBLE_MAT4x3 => |*value| c.glProgramUniformMatrix4x3dv(program, location, 1, c.GL_FALSE, value), + .SAMPLER_1D, .SAMPLER_2D, .SAMPLER_3D, .SAMPLER_CUBE, .SAMPLER_1D_SHADOW, .SAMPLER_2D_SHADOW, .SAMPLER_1D_ARRAY, .SAMPLER_2D_ARRAY, .SAMPLER_1D_ARRAY_SHADOW, .SAMPLER_2D_ARRAY_SHADOW, .SAMPLER_2D_MULTISAMPLE, .SAMPLER_2D_MULTISAMPLE_ARRAY, .SAMPLER_CUBE_SHADOW, .SAMPLER_BUFFER, .SAMPLER_2D_RECT, .SAMPLER_2D_RECT_SHADOW, .INT_SAMPLER_1D, .INT_SAMPLER_2D, .INT_SAMPLER_3D, .INT_SAMPLER_CUBE, .INT_SAMPLER_1D_ARRAY, .INT_SAMPLER_2D_ARRAY, .INT_SAMPLER_2D_MULTISAMPLE, .INT_SAMPLER_2D_MULTISAMPLE_ARRAY, .INT_SAMPLER_BUFFER, .INT_SAMPLER_2D_RECT, .UNSIGNED_INT_SAMPLER_1D, .UNSIGNED_INT_SAMPLER_2D, .UNSIGNED_INT_SAMPLER_3D, .UNSIGNED_INT_SAMPLER_CUBE, .UNSIGNED_INT_SAMPLER_1D_ARRAY, .UNSIGNED_INT_SAMPLER_2D_ARRAY, .UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, .UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, .UNSIGNED_INT_SAMPLER_BUFFER, .UNSIGNED_INT_SAMPLER_2D_RECT => |value| c.glProgramUniform1i(program, location, value), + else => unreachable, + } + } + + pub fn getShaderValue(self: *CachedUniform, shader: ShaderProgram) void { + const program = shader.program_id; + const location = self.location; + + switch (self.value) { + .FLOAT => |*value| c.glGetnUniformfv(program, location, @sizeOf(@TypeOf(value.*)), value), + .FLOAT_VEC2 => |*value| c.glGetnUniformfv(program, location, @sizeOf(@TypeOf(value.*)), value), + .FLOAT_VEC3 => |*value| c.glGetnUniformfv(program, location, @sizeOf(@TypeOf(value.*)), value), + .FLOAT_VEC4 => |*value| c.glGetnUniformfv(program, location, @sizeOf(@TypeOf(value.*)), value), + .DOUBLE => |*value| c.glGetnUniformdv(program, location, @sizeOf(@TypeOf(value.*)), value), + .DOUBLE_VEC2 => |*value| c.glGetnUniformdv(program, location, @sizeOf(@TypeOf(value.*)), value), + .DOUBLE_VEC3 => |*value| c.glGetnUniformdv(program, location, @sizeOf(@TypeOf(value.*)), value), + .DOUBLE_VEC4 => |*value| c.glGetnUniformdv(program, location, @sizeOf(@TypeOf(value.*)), value), + .INT => |*value| c.glGetnUniformiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .INT_VEC2 => |*value| c.glGetnUniformiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .INT_VEC3 => |*value| c.glGetnUniformiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .INT_VEC4 => |*value| c.glGetnUniformiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .UNSIGNED_INT => |*value| c.glGetnUniformuiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .UNSIGNED_INT_VEC2 => |*value| c.glGetnUniformuiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .UNSIGNED_INT_VEC3 => |*value| c.glGetnUniformuiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .UNSIGNED_INT_VEC4 => |*value| c.glGetnUniformuiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .BOOL => |*value| c.glGetnUniformuiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .BOOL_VEC2 => |*value| c.glGetnUniformuiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .BOOL_VEC3 => |*value| c.glGetnUniformuiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .BOOL_VEC4 => |*value| c.glGetnUniformuiv(program, location, @sizeOf(@TypeOf(value.*)), value), + .FLOAT_MAT2 => |*value| c.glGetUniformfv(program, location, value), + .FLOAT_MAT3 => |*value| c.glGetUniformfv(program, location, value), + .FLOAT_MAT4 => |*value| c.glGetUniformfv(program, location, value), + .FLOAT_MAT2x3 => |*value| c.glGetUniformfv(program, location, value), + .FLOAT_MAT2x4 => |*value| c.glGetUniformfv(program, location, value), + .FLOAT_MAT3x2 => |*value| c.glGetUniformfv(program, location, value), + .FLOAT_MAT3x4 => |*value| c.glGetUniformfv(program, location, value), + .FLOAT_MAT4x2 => |*value| c.glGetUniformfv(program, location, value), + .FLOAT_MAT4x3 => |*value| c.glGetUniformfv(program, location, value), + .DOUBLE_MAT2 => |*value| c.glGetUniformdv(program, location, value), + .DOUBLE_MAT3 => |*value| c.glGetUniformdv(program, location, value), + .DOUBLE_MAT4 => |*value| c.glGetUniformdv(program, location, value), + .DOUBLE_MAT2x3 => |*value| c.glGetUniformdv(program, location, value), + .DOUBLE_MAT2x4 => |*value| c.glGetUniformdv(program, location, value), + .DOUBLE_MAT3x2 => |*value| c.glGetUniformdv(program, location, value), + .DOUBLE_MAT3x4 => |*value| c.glGetUniformdv(program, location, value), + .DOUBLE_MAT4x2 => |*value| c.glGetUniformdv(program, location, value), + .DOUBLE_MAT4x3 => |*value| c.glGetUniformdv(program, location, value), + .SAMPLER_1D, .SAMPLER_2D, .SAMPLER_3D, .SAMPLER_CUBE, .SAMPLER_1D_SHADOW, .SAMPLER_2D_SHADOW, .SAMPLER_1D_ARRAY, .SAMPLER_2D_ARRAY, .SAMPLER_1D_ARRAY_SHADOW, .SAMPLER_2D_ARRAY_SHADOW, .SAMPLER_2D_MULTISAMPLE, .SAMPLER_2D_MULTISAMPLE_ARRAY, .SAMPLER_CUBE_SHADOW, .SAMPLER_BUFFER, .SAMPLER_2D_RECT, .SAMPLER_2D_RECT_SHADOW, .INT_SAMPLER_1D, .INT_SAMPLER_2D, .INT_SAMPLER_3D, .INT_SAMPLER_CUBE, .INT_SAMPLER_1D_ARRAY, .INT_SAMPLER_2D_ARRAY, .INT_SAMPLER_2D_MULTISAMPLE, .INT_SAMPLER_2D_MULTISAMPLE_ARRAY, .INT_SAMPLER_BUFFER, .INT_SAMPLER_2D_RECT, .UNSIGNED_INT_SAMPLER_1D, .UNSIGNED_INT_SAMPLER_2D, .UNSIGNED_INT_SAMPLER_3D, .UNSIGNED_INT_SAMPLER_CUBE, .UNSIGNED_INT_SAMPLER_1D_ARRAY, .UNSIGNED_INT_SAMPLER_2D_ARRAY, .UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, .UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, .UNSIGNED_INT_SAMPLER_BUFFER, .UNSIGNED_INT_SAMPLER_2D_RECT => |*value| c.glGetnUniformiv(program, location, @sizeOf(@TypeOf(value.*)), value), + else => unreachable, + } + } + // zig fmt: on +}; pub const ShaderProgram = struct { program_id: c.GLuint, @@ -27,30 +313,6 @@ pub const ShaderProgram = struct { return id; } - pub fn setUniform1i(self: ShaderProgram, uniform_id: c.GLint, value: c_int) void { - c.glUniform1i(uniform_id, value); - } - - pub fn setUniform1f(self: ShaderProgram, uniform_id: c.GLint, value: f32) void { - c.glUniform1f(uniform_id, value); - } - - pub fn setUniform2f(self: ShaderProgram, uniform_id: c.GLint, x: f32, y: f32) void { - c.glUniform2f(uniform_id, x, y); - } - - pub fn setUniform3f(self: ShaderProgram, uniform_id: c.GLint, x: f32, y: f32, z: f32) void { - c.glUniform3f(uniform_id, x, y, z); - } - - pub fn setUniform4f(self: ShaderProgram, uniform_id: c.GLint, x: f32, y: f32, z: f32, w: f32) void { - c.glUniform4f(uniform_id, x, y, z, w); - } - - 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(vert_source: []const u8, frag_source: []const u8) !ShaderProgram { var self: ShaderProgram = undefined; @@ -92,6 +354,69 @@ pub const ShaderProgram = struct { } }; +pub const UniformCache = struct { + uniforms: std.AutoHashMap([*]const u8, CachedUniform), + shader: *ShaderProgram, + + pub fn init(allocator: *std.mem.Allocator, shader: *ShaderProgram) UniformCache { + return UniformCache{ + .uniforms = std.AutoHashMap([*]const u8, CachedUniform).init(allocator), + .shader = shader, + }; + } + + pub fn deinit(self: *UniformCache) void { + self.uniforms.deinit(); + } + + pub fn refresh(self: *UniformCache) !void { + var uniform_count: c.GLint = undefined; + c.glGetProgramiv(self.shader.program_id, c.GL_ACTIVE_UNIFORMS, &uniform_count); + + const count = self.uniforms.count(); + var existing_names = try c_allocator.alloc([*]const u8, count); + defer c_allocator.free(existing_names); + var existing_indices = try c_allocator.alloc(c.GLuint, count); + defer c_allocator.free(existing_indices); + + { + var it = self.uniforms.iterator(); + var i: usize = 0; + while (it.next()) |entry| { + existing_names[i] = entry.key; + i += 1; + } + } + + c.glGetUniformIndices(self.shader.program_id, @intCast(c.GLsizei, count), existing_names.ptr, existing_indices.ptr); + + for (existing_indices) |index, i| { + const name = existing_names[i]; + if (index == c.GL_INVALID_INDEX) { + _ = self.uniforms.remove(name); + // @TODO: remove OSC link + } else { + var uniform = self.uniforms.get(name).?.value; + uniform.location = self.shader.uniformLocation(name) catch unreachable; + uniform.setShaderValue(self.shader.*); + } + } + } + + pub fn get(self: *UniformCache, name: [*]const u8) !?*CachedUniform { + var result = try self.uniforms.getOrPut(name); + if (!result.found_existing) { + result.kv.value = CachedUniform.init(self.shader.*, name) catch { + _ = self.uniforms.remove(name); + return null; + }; + // @TODO: add OSC link + } + + return &result.kv.value; + } +}; + fn initGlShader(source: []const u8, name: []const u8, kind: c.GLenum) !c.GLuint { const shader_id = c.glCreateShader(kind); errdefer c.glDeleteShader(shader_id); @@ -179,7 +504,7 @@ pub const VertexObject = struct { 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); + c.glBufferData(c.GL_ARRAY_BUFFER, @intCast(c_long, @sizeOf(T) * vertices.len), @ptrCast(*const c_void, vertices.ptr), c.GL_STATIC_DRAW); return self; } @@ -191,17 +516,16 @@ pub const VertexObject = struct { }; pub const Constants = struct { - textureShader: ShaderProgram, - normalizedQuad: VertexObject, + texture_shader: ShaderProgram, + normalized_quad: VertexObject, main_window: *c.GLFWwindow, + aspect: f32, + config: *cfg.Config, - pub fn create(main_window: *c.GLFWwindow) !Constants { - var self: Constants = undefined; - + pub fn create(main_window: *c.GLFWwindow, config: *cfg.Config) !Constants { c.glfwMakeContextCurrent(main_window); - self.main_window = main_window; - self.textureShader = try ShaderProgram.create( + const shader = try ShaderProgram.create( \\#version 330 core \\ \\layout(location = 0) in vec2 position; @@ -230,13 +554,18 @@ pub const Constants = struct { 1.0, -1.0, 1.0, 1.0, }; - self.normalizedQuad = VertexObject.create(f32, vertices[0..], 2); - return self; + return Constants{ + .main_window = main_window, + .texture_shader = shader, + .normalized_quad = VertexObject.create(f32, vertices[0..], 2), + .config = config, + .aspect = @intToFloat(f32, config.width) / @intToFloat(f32, config.height), + }; } pub fn destroy(self: *Constants) void { - self.normalizedQuad.destroy(); - self.textureShader.destroy(); + self.normalized_quad.destroy(); + self.texture_shader.destroy(); } }; diff --git a/src/main.zig b/src/main.zig index 0530024..37104da 100644 --- a/src/main.zig +++ b/src/main.zig @@ -51,7 +51,7 @@ pub fn main() !void { c.glfwMakeContextCurrent(window); c.glfwSwapInterval(1); - var constants = try gl.Constants.create(window); + var constants = try gl.Constants.create(window, &config); defer constants.destroy(); var outputs = try std.ArrayList(*out.Output).initCapacity(&arena.allocator, config.outputs.len); @@ -67,13 +67,12 @@ pub fn main() !void { c.glClearColor(0.0, 0.0, 0.0, 1.0); debug_gl.assertNoError(); + debug_gl.init(); const start_time = c.glfwGetTime(); var prev_time = start_time; - constants.normalizedQuad.bind(0); - - debug_gl.assertNoError(); + constants.normalized_quad.bind(0); var main_program = try gl.ShaderProgram.create( \\#version 330 core @@ -101,12 +100,17 @@ pub fn main() !void { var last_stat = try shader_file.stat(); try reloadShader(&main_program, shader_file, last_stat.size); + var cache = gl.UniformCache.init(std.heap.c_allocator, &main_program); + defer cache.deinit(); + var fbo = try gl.FramebufferObject.create(config.width, config.height); defer fbo.destroy(); const control = try ctrl.ControlServer.init(&arena.allocator, config.osc); defer control.destroy(); + _ = try cache.get("radius\x00"); + while (c.glfwWindowShouldClose(window) == c.GL_FALSE) { c.glfwMakeContextCurrent(window); c.glClear(c.GL_COLOR_BUFFER_BIT); @@ -118,16 +122,22 @@ pub fn main() !void { const stat = try shader_file.stat(); if (stat.mtime > last_stat.mtime) { try reloadShader(&main_program, shader_file, stat.size); + try cache.refresh(); last_stat = stat; } + if (try cache.get("offset\x00")) |offset| { + offset.value.FLOAT += 0.01; + offset.setShaderValue(main_program); + } + control.update(main_program); fbo.bind(); c.glClear(c.GL_COLOR_BUFFER_BIT); main_program.bind(); - constants.normalizedQuad.draw(); + constants.normalized_quad.draw(); fbo.unbind(); for (outputs.toSlice()) |output, i| { @@ -144,8 +154,6 @@ pub fn main() !void { c.glfwPollEvents(); } - - debug_gl.assertNoError(); } fn reloadShader(current: *gl.ShaderProgram, frag_file: fs.File, size: u64) !void { diff --git a/src/output.zig b/src/output.zig index c31c191..770c0ba 100644 --- a/src/output.zig +++ b/src/output.zig @@ -27,6 +27,8 @@ pub const WindowOutput = struct { window: *c.GLFWwindow, constants: *gl.Constants, + resized: bool = false, + pub fn create(allocator: *std.mem.Allocator, config: cfg.OutputConfig, constants: *gl.Constants) *Output { const self = allocator.create(WindowOutput) catch unreachable; @@ -40,38 +42,58 @@ pub const WindowOutput = struct { }, }; - c.glfwSetWindowUserPointer(self.*.window, @ptrCast(*c_void, self)); - _ = c.glfwSetKeyCallback(self.*.window, keyCallback); + c.glfwSetWindowUserPointer(self.window, @ptrCast(*c_void, self)); + _ = c.glfwSetKeyCallback(self.window, keyCallback); + _ = c.glfwSetFramebufferSizeCallback(self.window, sizeCallback); - c.glfwMakeContextCurrent(self.*.window); - constants.normalizedQuad.bind(0); + c.glfwMakeContextCurrent(self.window); + constants.normalized_quad.bind(0); - return &self.*.output; + return &self.output; } fn update(output: *Output, texture_id: c.GLuint) bool { const self = @fieldParentPtr(WindowOutput, "output", output); - if (c.glfwWindowShouldClose(self.*.window) == c.GL_TRUE) + if (c.glfwWindowShouldClose(self.window) == c.GL_TRUE) return true; - c.glfwMakeContextCurrent(self.*.window); + c.glfwMakeContextCurrent(self.window); c.glClear(c.GL_COLOR_BUFFER_BIT); + if (self.resized) { + var width: c_int = undefined; + var height: c_int = undefined; + var scaled_width: c_int = undefined; + var scaled_height: c_int = undefined; + + c.glfwGetFramebufferSize(self.window, &width, &height); + const window_aspect = @intToFloat(f32, width) / @intToFloat(f32, height); + if (window_aspect >= self.constants.aspect) { + scaled_height = height; + scaled_width = @floatToInt(c_int, @intToFloat(f32, height) * self.constants.aspect); + } else { + scaled_width = width; + scaled_height = @floatToInt(c_int, @intToFloat(f32, width) / self.constants.aspect); + } + + c.glViewport(@divFloor(width - scaled_width, 2), @divFloor(height - scaled_height, 2), scaled_width, scaled_height); + } + c.glBindTexture(c.GL_TEXTURE_2D, texture_id); c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4); - self.constants.textureShader.bind(); - self.constants.normalizedQuad.draw(); + self.constants.texture_shader.bind(); + self.constants.normalized_quad.draw(); - c.glfwSwapBuffers(self.*.window); + c.glfwSwapBuffers(self.window); return false; } fn destroy(output: *Output) void { const self = @fieldParentPtr(WindowOutput, "output", output); - c.glfwDestroyWindow(self.*.window); + c.glfwDestroyWindow(self.window); } fn keyCallback(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { @@ -85,4 +107,9 @@ pub const WindowOutput = struct { else => {}, } } + + fn sizeCallback(win: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { + const self = @ptrCast(*WindowOutput, @alignCast(@alignOf(WindowOutput), c.glfwGetWindowUserPointer(win).?)); + self.resized = true; + } }; |
