aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-01-24 14:32:29 +0000
committers-ol <s-ol@users.noreply.github.com>2020-01-25 15:06:20 +0000
commit84a3bbf2bffa04d6bb0d3b038473467dd573c9d3 (patch)
tree7059479d35048b9cdce421706e2f98ca26c78a28
parenthot reloading (diff)
downloadglsl-view-84a3bbf2bffa04d6bb0d3b038473467dd573c9d3.tar.gz
glsl-view-84a3bbf2bffa04d6bb0d3b038473467dd573c9d3.zip
basic OSC support
-rw-r--r--build.zig1
-rw-r--r--config.yaml2
-rw-r--r--shaders/test.frag12
-rw-r--r--src/c.zig1
-rw-r--r--src/config.zig2
-rw-r--r--src/control.zig77
-rw-r--r--src/gl.zig65
-rw-r--r--src/main.zig30
-rw-r--r--src/output.zig5
9 files changed, 144 insertions, 51 deletions
diff --git a/build.zig b/build.zig
index 33a955c..6e55328 100644
--- a/build.zig
+++ b/build.zig
@@ -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;
+}
diff --git a/src/c.zig b/src/c.zig
index 7a13fde..427b3d6 100644
--- a/src/c.zig
+++ b/src/c.zig
@@ -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;
+ }
+};
diff --git a/src/gl.zig b/src/gl.zig
index bd2c652..659911e 100644
--- a/src/gl.zig
+++ b/src/gl.zig
@@ -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