diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-01-24 14:32:29 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-01-25 15:06:20 +0000 |
| commit | 84a3bbf2bffa04d6bb0d3b038473467dd573c9d3 (patch) | |
| tree | 7059479d35048b9cdce421706e2f98ca26c78a28 | |
| parent | hot reloading (diff) | |
| download | glsl-view-84a3bbf2bffa04d6bb0d3b038473467dd573c9d3.tar.gz glsl-view-84a3bbf2bffa04d6bb0d3b038473467dd573c9d3.zip | |
basic OSC support
| -rw-r--r-- | build.zig | 1 | ||||
| -rw-r--r-- | config.yaml | 2 | ||||
| -rw-r--r-- | shaders/test.frag | 12 | ||||
| -rw-r--r-- | src/c.zig | 1 | ||||
| -rw-r--r-- | src/config.zig | 2 | ||||
| -rw-r--r-- | src/control.zig | 77 | ||||
| -rw-r--r-- | src/gl.zig | 65 | ||||
| -rw-r--r-- | src/main.zig | 30 | ||||
| -rw-r--r-- | src/output.zig | 5 |
9 files changed, 144 insertions, 51 deletions
@@ -8,6 +8,7 @@ pub fn build(b: *Builder) void { exe.linkSystemLibrary("yaml"); exe.linkSystemLibrary("glfw"); exe.linkSystemLibrary("epoxy"); + exe.linkSystemLibrary("lo"); exe.install(); const run_cmd = exe.run(); diff --git a/config.yaml b/config.yaml index fcac769..7bdcaa8 100644 --- a/config.yaml +++ b/config.yaml @@ -1,4 +1,4 @@ -fragment: swag.frag +fragment: shaders/test.frag width: 480 height: 270 outputs: diff --git a/shaders/test.frag b/shaders/test.frag new file mode 100644 index 0000000..d9b76c1 --- /dev/null +++ b/shaders/test.frag @@ -0,0 +1,12 @@ +#version 330 core + +in vec2 uv; +out vec4 color; + +uniform float offset; +uniform float r; + +void main() { + color = vec4(mod(uv.xyx + offset + vec2(0,0.5).xxy, vec3(1)), 1); + color.r = r; +} @@ -2,4 +2,5 @@ pub usingnamespace @cImport({ @cInclude("epoxy/gl.h"); @cInclude("GLFW/glfw3.h"); @cInclude("yaml.h"); + @cInclude("lo/lo.h"); }); diff --git a/src/config.zig b/src/config.zig index 7e1e78f..3ef8a9e 100644 --- a/src/config.zig +++ b/src/config.zig @@ -13,7 +13,7 @@ pub const OutputConfig = struct { height: i32, // only for 'window' - monitor: []const u8, + monitor: []const u8, fullscreen: bool, }; diff --git a/src/control.zig b/src/control.zig new file mode 100644 index 0000000..4937bb7 --- /dev/null +++ b/src/control.zig @@ -0,0 +1,77 @@ +const c = @import("c.zig"); +const gl = @import("gl.zig"); +const std = @import("std"); + +const param_prefix = "/param/"; + +pub const ControlServer = struct { + server: c.lo_server, + shader: gl.ShaderProgram, + + pub fn init(allocator: *std.mem.Allocator) !*ControlServer { + var self: *ControlServer = try allocator.create(ControlServer); + + self.server = c.lo_server_new("1234", handle_error); + _ = c.lo_server_add_method(self.server, null, null, handle_method, @ptrCast(*c_void, self)); + + return self; + } + + pub fn update(self: *ControlServer, shader: gl.ShaderProgram) void { + self.shader = shader; + while (c.lo_server_recv_noblock(self.server, 0) > 0) {} + } + + pub fn destroy(self: ControlServer) void { + c.lo_server_free(self.server); + } + + fn handle_error(num: c_int, msg: [*c]const u8, where: [*c]const u8) callconv(.C) void { + std.debug.warn("OSC error {} @ {s}: {s}\n", .{ num, @ptrCast([*:0]const u8, where), @ptrCast([*:0]const u8, msg) }); + } + + fn handle_method(_path: [*c]const u8, _types: [*c]const u8, argv: [*c][*c]c.lo_arg, argc: c_int, msg: c.lo_message, userdata: ?*c_void) callconv(.C) c_int { + const self = @ptrCast(*ControlServer, @alignCast(@alignOf(ControlServer), userdata.?)); + 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.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}); + } + return 0; + } + + std.debug.warn("unhandled OSC message {s} ({s})\n", .{ path, types }); + return 1; + } + + fn handle_bundle_start(time: c.lo_timetag, userdata: ?*c_void) callconv(.C) c_int { + return 1; + } + fn handle_bundle_end(userdata: ?*c_void) callconv(.C) c_int { + return 1; + } +}; @@ -20,32 +20,31 @@ pub const ShaderProgram = struct { return id; } - pub fn uniformLocation(self: ShaderProgram, name: [*]const u8) c.GLint { + 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}); - } + if (id == -1) + return error.invalidUniform; return id; } - pub fn setUniformInt(self: ShaderProgram, uniform_id: c.GLint, value: c_int) void { + pub fn setUniform1i(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 { + pub fn setUniform1f(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 setUniform2f(self: ShaderProgram, uniform_id: c.GLint, x: f32, y: f32) void { + c.glUniform2f(uniform_id, x, y); } - pub fn setUniformVec3(self: ShaderProgram, uniform_id: c.GLint, value: [3]f32) void { - c.glUniform3fv(uniform_id, 1, value.ptr); + 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 setUniformVec4(self: ShaderProgram, uniform_id: c.GLint, value: [4]f32) void { - c.glUniform4fv(uniform_id, 1, value.ptr); + 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 { @@ -54,10 +53,10 @@ pub const ShaderProgram = struct { pub fn create(vert_source: []const u8, frag_source: []const u8) !ShaderProgram { var self: ShaderProgram = undefined; - + self.vert_id = try initGlShader(vert_source, "vertex", c.GL_VERTEX_SHADER); errdefer c.glDeleteShader(self.vert_id); - + self.frag_id = try initGlShader(frag_source, "fragment", c.GL_FRAGMENT_SHADER); errdefer c.glDeleteShader(self.frag_id); @@ -65,7 +64,7 @@ pub const ShaderProgram = struct { c.glAttachShader(self.program_id, self.vert_id); c.glAttachShader(self.program_id, self.frag_id); c.glLinkProgram(self.program_id); - + errdefer c.glDeleteProgram(self.program_id); errdefer c.glDetachShader(self.program_id, self.frag_id); errdefer c.glDetachShader(self.program_id, self.vert_id); @@ -78,7 +77,7 @@ pub const ShaderProgram = struct { 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); - std.debug.warn("Error linking shader program: {s}\n", .{ @ptrCast([*:0]const u8, message.ptr) }); + std.debug.warn("Error linking shader program: {s}\n", .{@ptrCast([*:0]const u8, message.ptr)}); return error.LinkError; } @@ -117,7 +116,7 @@ fn initGlShader(source: []const u8, name: []const u8, kind: c.GLenum) !c.GLuint 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); } @@ -130,7 +129,7 @@ pub const FramebufferObject = struct { 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); @@ -140,10 +139,9 @@ pub const FramebufferObject = struct { 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; } @@ -159,13 +157,13 @@ pub const VertexObject = struct { 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); } @@ -175,20 +173,17 @@ pub const VertexObject = struct { 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); + 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); @@ -202,10 +197,10 @@ pub const Constants = struct { 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 \\ @@ -231,9 +226,9 @@ pub const Constants = struct { const vertices = [_]c.GLfloat{ -1.0, -1.0, - -1.0, 1.0, - 1.0, -1.0, - 1.0, 1.0, + -1.0, 1.0, + 1.0, -1.0, + 1.0, 1.0, }; self.normalizedQuad = VertexObject.create(f32, vertices[0..], 2); diff --git a/src/main.zig b/src/main.zig index 6c2b0c4..41ad341 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6,11 +6,12 @@ const debug_gl = @import("debug_gl.zig"); const cfg = @import("config.zig"); const out = @import("output.zig"); const gl = @import("gl.zig"); +const ctrl = @import("control.zig"); const c_allocator = @import("std").heap.c_allocator; var window: *c.GLFWwindow = undefined; -extern fn errorCallback(err: c_int, description: [*c]const u8) callconv(.C) void { +fn errorCallback(err: c_int, description: [*c]const u8) callconv(.C) void { panic("Error: {}\n", .{description}); } @@ -28,7 +29,7 @@ pub fn main() !void { var monitor_count: c_int = 0; const monitors = c.glfwGetMonitors(&monitor_count); for (monitors[0..@intCast(usize, monitor_count)]) |monitor, i| { - std.debug.warn("monitor {}: '{s}'\n", .{ i, @ptrCast([*:0]const u8, c.glfwGetMonitorName(monitor))}); + std.debug.warn("monitor {}: '{s}'\n", .{ i, @ptrCast([*:0]const u8, c.glfwGetMonitorName(monitor)) }); } c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 4); @@ -44,13 +45,13 @@ pub fn main() !void { panic("unable to create window\n", .{}); }; defer c.glfwDestroyWindow(window); - + c.glfwMakeContextCurrent(window); c.glfwSwapInterval(1); var constants = try gl.Constants.create(window); defer constants.destroy(); - + var outputs = try std.ArrayList(*out.Output).initCapacity(&config.arena.allocator, config.outputs.len); defer outputs.deinit(); for (config.outputs) |output_config, i| { @@ -104,7 +105,10 @@ pub fn main() !void { defer fbo.destroy(); var offset: f32 = 0; - + + const control = try ctrl.ControlServer.init(&config.arena.allocator); + defer control.destroy(); + while (c.glfwWindowShouldClose(window) == c.GL_FALSE) { c.glfwMakeContextCurrent(window); c.glClear(c.GL_COLOR_BUFFER_BIT); @@ -119,15 +123,19 @@ pub fn main() !void { last_stat = stat; } + control.update(main_program); + fbo.bind(); c.glClear(c.GL_COLOR_BUFFER_BIT); - + main_program.bind(); offset += @floatCast(f32, elapsed / 4); - main_program.setUniformFloat(main_program.uniformLocation("offset"), offset); + if (main_program.uniformLocation("offset")) |location| { + main_program.setUniform1f(location, offset); + } else |_| {} constants.normalizedQuad.draw(); fbo.unbind(); - + for (outputs.toSlice()) |output, i| { const close = output.update(output, fbo.texture_id); if (close) { @@ -139,7 +147,7 @@ pub fn main() !void { if (outputs.len == 0) break; - + c.glfwPollEvents(); } @@ -163,11 +171,11 @@ fn reloadShader(current: *gl.ShaderProgram, frag_file: fs.File, size: u64) !void \\ gl_Position = vec4(position, 0, 1); \\} ; - + if (gl.ShaderProgram.create(vert_source, frag_source[0..length])) |new_program| { current.destroy(); current.* = new_program; } else |err| { - std.debug.warn("Error while reloading shader:{}\n", .{ err }); + std.debug.warn("Error while reloading shader:{}\n", .{err}); } } diff --git a/src/output.zig b/src/output.zig index be3b3dd..b2368d8 100644 --- a/src/output.zig +++ b/src/output.zig @@ -63,7 +63,7 @@ pub const WindowOutput = struct { self.constants.textureShader.bind(); self.constants.normalizedQuad.draw(); - + c.glfwSwapBuffers(self.*.window); return false; } @@ -74,11 +74,10 @@ pub const WindowOutput = struct { c.glfwDestroyWindow(self.*.window); } - extern fn keyCallback(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { + fn keyCallback(win: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { if (action != c.GLFW_PRESS) return; const self = @ptrCast(*WindowOutput, @alignCast(@alignOf(WindowOutput), c.glfwGetWindowUserPointer(win).?)); - std.debug.warn("key pressed: {}\n", .{ key }); switch (key) { // c.GLFW_KEY_F => // toggle fullscreen // c.GLFW_KEY_LEFT => // cycle through monitors |
