aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build.zig1
-rw-r--r--src/c.zig1
-rw-r--r--src/config.zig309
-rw-r--r--src/control.zig206
-rw-r--r--src/gl.zig165
-rw-r--r--src/main.zig130
-rw-r--r--src/output.zig73
7 files changed, 283 insertions, 602 deletions
diff --git a/build.zig b/build.zig
index 30aea09..fbee00c 100644
--- a/build.zig
+++ b/build.zig
@@ -22,7 +22,6 @@ pub fn build(b: *std.Build) void {
exe.root_module.addOptions("build_config", options);
exe.linkLibC();
- exe.linkSystemLibrary("yaml-0.1");
exe.linkSystemLibrary("glfw3");
exe.linkSystemLibrary("epoxy");
exe.linkSystemLibrary("liblo");
diff --git a/src/c.zig b/src/c.zig
index fd837a3..944cfc8 100644
--- a/src/c.zig
+++ b/src/c.zig
@@ -3,7 +3,6 @@ const build_config = @import("build_config");
pub usingnamespace @cImport({
@cInclude("epoxy/gl.h");
@cInclude("GLFW/glfw3.h");
- @cInclude("yaml.h");
@cInclude("lo/lo.h");
if (build_config.have_ffmpeg) {
diff --git a/src/config.zig b/src/config.zig
index 97985c9..529b3bd 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -1,305 +1,58 @@
-const c = @import("c.zig");
-const fs = @import("std").fs;
const std = @import("std");
const debug = @import("std").debug;
-const yaml = @import("yaml.zig");
const out = @import("output.zig");
pub const OutputConfig = union(enum) {
window: out.WindowOutput.Config,
texture_share_vk: out.TSVOutput.Config,
-};
-pub const ParameterConfig = struct {
- name: []const u8,
- type: []const u8,
+ const default: OutputConfig = .{ .window = .default };
};
-pub const OSCConfig = union(enum) {
- const Protocol = enum {
- udp,
- tcp,
- unix,
- };
-
- Manual: struct {
- protocol: Protocol = Protocol.udp,
- port: u16 = 9000,
- },
- URL: []const u8,
-};
+fn parseInt(it: *std.process.ArgIterator, comptime T: type) !T {
+ const value = it.next() orelse return error.missingArgument;
+ return try std.fmt.parseInt(T, value, 10);
+}
-const defaultOutput: OutputConfig = .{ .window = .default };
+fn parseString(it: *std.process.ArgIterator, allocator: std.mem.Allocator) ![]u8 {
+ const value = it.next() orelse return error.missingArgument;
+ return allocator.dupe(u8, value);
+}
pub const Config = struct {
width: i32,
height: i32,
outputs: []const OutputConfig,
- fragment: []const u8,
- parameters: []const ParameterConfig,
- project_root: fs.Dir,
- osc: OSCConfig,
+ osc: []const u8,
- pub fn parse(allocator: std.mem.Allocator, filename: []const u8) !Config {
- var parser: c.yaml_parser_t = undefined;
- _ = c.yaml_parser_initialize(&parser);
- defer c.yaml_parser_delete(&parser);
-
- 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);
-
- const dirname = fs.path.dirname(filename) orelse ".";
- debug.print("file/dirname is {s} / {s}\n", .{ filename, dirname });
- var config: Config = .{
- .width = 1920,
- .height = 1080,
- .outputs = ([_]OutputConfig{defaultOutput})[0..],
- .fragment = "",
- .parameters = ([0]ParameterConfig{})[0..],
- .project_root = try fs.cwd().openDir(dirname, .{}),
- .osc = .{ .URL = "osc.udp://:9000" },
- };
+ pub const default: Config = .{
+ .width = 1920,
+ .height = 1080,
+ .outputs = ([_]OutputConfig{.default})[0..],
+ .osc = "osc.udp://:9000",
+ };
- try yaml.expectEvent(&parser, c.YAML_STREAM_START_EVENT);
- try yaml.expectEvent(&parser, c.YAML_DOCUMENT_START_EVENT);
- try yaml.expectEvent(&parser, c.YAML_MAPPING_START_EVENT);
+ pub fn init(allocator: std.mem.Allocator) !Config {
+ var config: Config = .default;
- while (true) {
- var event: c.yaml_event_t = undefined;
- if (c.yaml_parser_parse(&parser, &event) != 1)
- return error.YAMLParserError;
- defer c.yaml_event_delete(&event);
+ var it = try std.process.argsWithAllocator(allocator);
+ defer it.deinit();
- switch (event.type) {
- c.YAML_MAPPING_END_EVENT => break,
- c.YAML_SCALAR_EVENT => {
- const data = event.data.scalar;
- const key: []const u8 = data.value[0..data.length];
+ _ = it.skip();
- if (std.mem.eql(u8, key, "width")) {
- config.width = try yaml.parseInt(&parser, i32);
- } else if (std.mem.eql(u8, key, "height")) {
- config.height = try yaml.parseInt(&parser, i32);
- } else if (std.mem.eql(u8, key, "fragment")) {
- config.fragment = try yaml.parseString(&parser, allocator);
- } else if (std.mem.eql(u8, key, "outputs")) {
- config.outputs = try parseOutputs(&parser, allocator);
- } else if (std.mem.eql(u8, key, "parameters")) {
- config.parameters = try parseParameters(&parser, allocator);
- } else if (std.mem.eql(u8, key, "project_root")) {
- config.project_root = try fs.cwd().openDir(try yaml.parseString(&parser, allocator), .{});
- } else if (std.mem.eql(u8, key, "osc")) {
- config.osc = try parseOSC(&parser, allocator);
- } else {
- debug.print("unknown key: '{s}'\n", .{key});
- try yaml.skipAny(&parser);
- }
- },
- else => {
- debug.print("unexpected event: {}\n", .{event.type});
- return error.InvalidConfiguration;
- },
+ while (it.next()) |arg| {
+ if (std.mem.eql(u8, arg, "--width")) {
+ config.width = try parseInt(&it, i32);
+ } else if (std.mem.eql(u8, arg, "--height")) {
+ config.height = try parseInt(&it, i32);
+ } else if (std.mem.eql(u8, arg, "--osc")) {
+ config.osc = try parseString(&it, allocator);
+ } else {
+ return error.invalidArgument;
}
+ // @TODO: output config
}
- try yaml.expectEvent(&parser, c.YAML_DOCUMENT_END_EVENT);
- try yaml.expectEvent(&parser, c.YAML_STREAM_END_EVENT);
-
return config;
}
};
-
-fn parseOutputs(parser: *c.yaml_parser_t, allocator: std.mem.Allocator) ![]OutputConfig {
- try yaml.expectEvent(parser, c.YAML_SEQUENCE_START_EVENT);
-
- var outputs = try allocator.alloc(OutputConfig, 1024);
- var output_count: usize = 0;
-
- while (true) {
- outputs[output_count] = yaml.parseUnion(parser, OutputConfig, allocator) catch |err| {
- if (err == error.InvalidType) break;
- return err;
- };
- output_count += 1;
-
- // var seqEvent: c.yaml_event_t = undefined;
- // if (c.yaml_parser_parse(parser, &seqEvent) != 1)
- // return error.YAMLParserError;
- // defer c.yaml_event_delete(&seqEvent);
-
- // switch (seqEvent.type) {
- // c.YAML_SEQUENCE_END_EVENT => break,
- // c.YAML_MAPPING_START_EVENT => {
- // const output = &outputs[output_count];
- // output.* = defaultOutput;
- //
- // while (true) {
- // var event: c.yaml_event_t = undefined;
- // if (c.yaml_parser_parse(parser, &event) != 1)
- // return error.YAMLParserError;
- // defer c.yaml_event_delete(&event);
- //
- // switch (event.type) {
- // c.YAML_MAPPING_END_EVENT => break,
- // c.YAML_SCALAR_EVENT => {
- // const data = event.data.scalar;
- // const key: []const u8 = data.value[0..data.length];
- //
- // if (!std.mem.eql(u8, key, "type")) {
- // const ouput_type = try yaml.parseEnum(parser, OutputConfig.Type);
- // output.* = switch (ouput_type) {
- // inline else => |t| {
- //
- // }
- // }
- // }
- //
- // if (std.mem.eql(u8, key, "width")) {
- // output.*.width = try yaml.parseInt(parser, i32);
- // } else if (std.mem.eql(u8, key, "height")) {
- // output.*.height = try yaml.parseInt(parser, i32);
- // } else if (std.mem.eql(u8, key, "filter")) {
- // output.*.filter = try yaml.parseEnum(parser, OutputConfig.FilterMode);
- // } else if (std.mem.eql(u8, key, "monitor")) {
- // output.*.monitor = try yaml.parseString(parser, allocator);
- // } else if (std.mem.eql(u8, key, "fullscreen")) {
- // output.*.fullscreen = try yaml.parseBool(parser);
- // } else {
- // debug.print("unknown key: '{s}'\n", .{key});
- // try yaml.skipAny(parser);
- // }
- // },
- // else => {
- // debug.print("unexpected event: {}\n", .{event.type});
- // return error.InvalidConfiguration;
- // },
- // }
- // }
- //
- // output_count += 1;
- // },
- // else => {
- // debug.print("unexpected event: {}\n", .{seqEvent.type});
- // return error.InvalidConfiguration;
- // },
- // }
- }
-
- _ = allocator.realloc(outputs, output_count) catch 0;
- return outputs[0..output_count];
-}
-
-fn parseParameters(parser: *c.yaml_parser_t, allocator: std.mem.Allocator) ![]ParameterConfig {
- try yaml.expectEvent(parser, c.YAML_SEQUENCE_START_EVENT);
-
- var parameters = try allocator.alloc(ParameterConfig, 1024);
- var param_count: usize = 0;
-
- while (true) {
- var seqEvent: c.yaml_event_t = undefined;
- if (c.yaml_parser_parse(parser, &seqEvent) != 1)
- return error.YAMLParserError;
- defer c.yaml_event_delete(&seqEvent);
-
- switch (seqEvent.type) {
- c.YAML_SEQUENCE_END_EVENT => break,
- c.YAML_MAPPING_START_EVENT => {
- const param = &parameters[param_count];
- var have_name = false;
- var have_type = false;
-
- while (true) {
- var event: c.yaml_event_t = undefined;
- if (c.yaml_parser_parse(parser, &event) != 1)
- return error.YAMLParserError;
- defer c.yaml_event_delete(&event);
-
- switch (event.type) {
- c.YAML_MAPPING_END_EVENT => break,
- c.YAML_SCALAR_EVENT => {
- const data = event.data.scalar;
- const key: []const u8 = data.value[0..data.length];
-
- if (std.mem.eql(u8, key, "name")) {
- param.*.name = try yaml.parseString(parser, allocator);
- have_name = true;
- } else if (std.mem.eql(u8, key, "type")) {
- param.*.type = try yaml.parseString(parser, allocator);
- have_type = true;
- } else {
- debug.print("unknown key: '{s}'\n", .{key});
- try yaml.skipAny(parser);
- }
- },
- else => {
- debug.print("unexpected event: {}\n", .{event.type});
- return error.InvalidConfiguration;
- },
- }
- }
-
- if (!(have_name and have_type)) {
- debug.print("name and type are mandatory for parameters.\n", .{});
- return error.InvalidConfiguration;
- }
-
- param_count += 1;
- },
- else => {
- debug.print("unexpected event: {}\n", .{seqEvent.type});
- return error.InvalidConfiguration;
- },
- }
- }
-
- _ = allocator.realloc(parameters, param_count) catch 0;
- return parameters[0..param_count];
-}
-
-fn parseOSC(parser: *c.yaml_parser_t, allocator: std.mem.Allocator) !OSCConfig {
- var event: c.yaml_event_t = undefined;
- if (c.yaml_parser_parse(parser, &event) != 1)
- return error.YAMLParserError;
- defer c.yaml_event_delete(&event);
-
- if (event.type == c.YAML_SCALAR_EVENT) {
- const url = try yaml.parseStringEvent(&event, allocator);
- return OSCConfig{ .URL = url };
- } else if (event.type != c.YAML_MAPPING_START_EVENT) {
- debug.print("unexpected event: {}\n", .{event.type});
- return error.InvalidConfiguration;
- }
-
- var config: OSCConfig = .{ .Manual = .{} };
-
- while (true) {
- if (c.yaml_parser_parse(parser, &event) != 1)
- return error.YAMLParserError;
- defer c.yaml_event_delete(&event);
-
- switch (event.type) {
- c.YAML_MAPPING_END_EVENT => break,
- c.YAML_SCALAR_EVENT => {
- const data = event.data.scalar;
- const key: []const u8 = data.value[0..data.length];
-
- if (std.mem.eql(u8, key, "protocol")) {
- config.Manual.protocol = try yaml.parseEnum(parser, OSCConfig.Protocol);
- } else if (std.mem.eql(u8, key, "port")) {
- config.Manual.port = try yaml.parseInt(parser, u16);
- } else {
- debug.print("unknown key: '{s}'\n", .{key});
- try yaml.skipAny(parser);
- }
- },
- else => {
- debug.print("unexpected event: {}\n", .{event.type});
- return error.InvalidConfiguration;
- },
- }
- }
-
- return config;
-}
diff --git a/src/control.zig b/src/control.zig
index 0ea6712..72abf6f 100644
--- a/src/control.zig
+++ b/src/control.zig
@@ -16,11 +16,10 @@ fn verify_args(expected: u8, got: []const u8) !void {
fn set_one(
comptime T: type,
dest: *T,
- argc: c_int,
- argv: [*c][*c]c.lo_arg,
+ argv: [][*c]c.lo_arg,
types: []const u8,
) !void {
- if (argc != 1)
+ if (types.len != 1)
return error.sizeMismatch;
switch (T) {
@@ -50,11 +49,10 @@ fn set_one(
fn set_array(
comptime T: type,
dest: []T,
- argc: c_int,
- argv: [*c][*c]c.lo_arg,
+ argv: [][*c]c.lo_arg,
types: []const u8,
) !void {
- if (argc != dest.len)
+ if (types.len != dest.len)
return error.sizeMismatch;
switch (T) {
@@ -88,14 +86,12 @@ fn set_array(
fn set_texture(
progress: std.Progress.Node,
- project_root: std.fs.Dir,
dest: *?gl.Texture,
texture_type: gl.Texture.Type,
- argc: c_int,
- argv: [*c][*c]c.lo_arg,
+ argv: [][*c]c.lo_arg,
types: []const u8,
) !void {
- if (argc != 1 or types[0] != 's') return error.invalidType;
+ if (types.len != 1 or types[0] != 's') return error.invalidType;
if (dest.*) |old| {
old.destroy();
@@ -103,7 +99,7 @@ fn set_texture(
}
var buffer: [1024]u8 = undefined;
- const filepath = try project_root.realpathZ(@ptrCast(&argv[0].*.s), buffer[0..]);
+ const filepath = try std.fs.cwd().realpathZ(@ptrCast(&argv[0].*.s), buffer[0..]);
buffer[filepath.len] = 0;
dest.* = try video.loadVideo(progress, @ptrCast(filepath), texture_type);
@@ -111,7 +107,6 @@ fn set_texture(
pub const ControlServer = struct {
server: c.lo_server,
- reload_requested: bool,
cache: *gl.UniformCache,
config: *cfg.Config,
@@ -127,7 +122,6 @@ pub const ControlServer = struct {
var self: *ControlServer = try allocator.create(ControlServer);
self.* = .{
.server = null,
- .reload_requested = false,
.cache = cache,
.config = config,
@@ -135,31 +129,15 @@ pub const ControlServer = struct {
.allocator = allocator,
};
- switch (config.osc) {
- .Manual => |conf| {
- var port = [_]u8{0} ** 6;
- _ = std.fmt.formatIntBuf(port[0..], conf.port, 10, .lower, std.fmt.FormatOptions{});
- const proto: c_int = switch (conf.protocol) {
- .udp => c.LO_UDP,
- .tcp => c.LO_TCP,
- .unix => c.LO_UNIX,
- };
-
- std.debug.print(
- "listening for OSC messages on {} port {}\n",
- .{ conf.protocol, conf.port },
- );
- self.server = c.lo_server_new_with_proto(port[0..], proto, handle_error);
- },
- .URL => |url| {
- std.debug.print("listening for OSC messages at {s}\n", .{url});
- self.server = c.lo_server_new_from_url(url[0..].ptr, handle_error);
- },
- }
+ std.debug.print("listening for OSC messages at {s}\n", .{config.osc});
+ self.server = c.lo_server_new_from_url(config.osc.ptr, handle_error);
if (self.server == null)
return error.serverInitializationError;
- _ = c.lo_server_add_method(self.server, null, null, handle_method, @as(*anyopaque, @ptrCast(self)));
+
+ _ = c.lo_server_add_method(self.server, "/-/shader", "s", handle_shader, @as(*anyopaque, @ptrCast(self)));
+ // _ = c.lo_server_add_method(self.server, "/-/reload", "", handle_reload, @as(*anyopaque, @ptrCast(self)));
+ _ = c.lo_server_add_method(self.server, "/*", null, handle_uniform, @as(*anyopaque, @ptrCast(self)));
return self;
}
@@ -182,8 +160,7 @@ pub const ControlServer = struct {
fn set_uniform(
self: *ControlServer,
path: []const u8,
- argv: [*c][*c]c.lo_arg,
- argc: c_int,
+ argv: [][*c]c.lo_arg,
types: []const u8,
) !void {
var parts = std.mem.tokenizeScalar(u8, path, '/');
@@ -217,61 +194,61 @@ pub const ControlServer = struct {
}
try switch (value) {
- .FLOAT => |val| set_one(f32, val, argc, argv, types),
- .DOUBLE => |val| set_one(f64, val, argc, argv, types),
- .INT => |val| set_one(i32, val, argc, argv, types),
- .UNSIGNED_INT => |val| set_one(u32, val, argc, argv, types),
- .BOOL => |val| set_one(u32, val, argc, argv, types),
- .FLOAT_VEC2 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .FLOAT_VEC3 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .FLOAT_VEC4 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .DOUBLE_VEC2 => |val| set_array(f64, val.*[0..], argc, argv, types),
- .DOUBLE_VEC3 => |val| set_array(f64, val.*[0..], argc, argv, types),
- .DOUBLE_VEC4 => |val| set_array(f64, val.*[0..], argc, argv, types),
- .INT_VEC2 => |val| set_array(i32, val.*[0..], argc, argv, types),
- .INT_VEC3 => |val| set_array(i32, val.*[0..], argc, argv, types),
- .INT_VEC4 => |val| set_array(i32, val.*[0..], argc, argv, types),
- .UNSIGNED_INT_VEC2 => |val| set_array(u32, val.*[0..], argc, argv, types),
- .UNSIGNED_INT_VEC3 => |val| set_array(u32, val.*[0..], argc, argv, types),
- .UNSIGNED_INT_VEC4 => |val| set_array(u32, val.*[0..], argc, argv, types),
- .BOOL_VEC2 => |val| set_array(u32, val.*[0..], argc, argv, types),
- .BOOL_VEC3 => |val| set_array(u32, val.*[0..], argc, argv, types),
- .BOOL_VEC4 => |val| set_array(u32, val.*[0..], argc, argv, types),
- .FLOAT_MAT2 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .FLOAT_MAT3 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .FLOAT_MAT4 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .FLOAT_MAT2x3 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .FLOAT_MAT2x4 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .FLOAT_MAT3x2 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .FLOAT_MAT3x4 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .FLOAT_MAT4x2 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .FLOAT_MAT4x3 => |val| set_array(f32, val.*[0..], argc, argv, types),
- .DOUBLE_MAT2 => |val| set_array(f64, val.*[0..], argc, argv, types),
- .DOUBLE_MAT3 => |val| set_array(f64, val.*[0..], argc, argv, types),
- .DOUBLE_MAT4 => |val| set_array(f64, val.*[0..], argc, argv, types),
- .DOUBLE_MAT2x3 => |val| set_array(f64, val.*[0..], argc, argv, types),
- .DOUBLE_MAT2x4 => |val| set_array(f64, val.*[0..], argc, argv, types),
- .DOUBLE_MAT3x2 => |val| set_array(f64, val.*[0..], argc, argv, types),
- .DOUBLE_MAT3x4 => |val| set_array(f64, val.*[0..], argc, argv, types),
- .DOUBLE_MAT4x2 => |val| set_array(f64, val.*[0..], argc, argv, types),
- .DOUBLE_MAT4x3 => |val| set_array(f64, val.*[0..], argc, argv, types),
+ .FLOAT => |val| set_one(f32, val, argv, types),
+ .DOUBLE => |val| set_one(f64, val, argv, types),
+ .INT => |val| set_one(i32, val, argv, types),
+ .UNSIGNED_INT => |val| set_one(u32, val, argv, types),
+ .BOOL => |val| set_one(u32, val, argv, types),
+ .FLOAT_VEC2 => |val| set_array(f32, val.*[0..], argv, types),
+ .FLOAT_VEC3 => |val| set_array(f32, val.*[0..], argv, types),
+ .FLOAT_VEC4 => |val| set_array(f32, val.*[0..], argv, types),
+ .DOUBLE_VEC2 => |val| set_array(f64, val.*[0..], argv, types),
+ .DOUBLE_VEC3 => |val| set_array(f64, val.*[0..], argv, types),
+ .DOUBLE_VEC4 => |val| set_array(f64, val.*[0..], argv, types),
+ .INT_VEC2 => |val| set_array(i32, val.*[0..], argv, types),
+ .INT_VEC3 => |val| set_array(i32, val.*[0..], argv, types),
+ .INT_VEC4 => |val| set_array(i32, val.*[0..], argv, types),
+ .UNSIGNED_INT_VEC2 => |val| set_array(u32, val.*[0..], argv, types),
+ .UNSIGNED_INT_VEC3 => |val| set_array(u32, val.*[0..], argv, types),
+ .UNSIGNED_INT_VEC4 => |val| set_array(u32, val.*[0..], argv, types),
+ .BOOL_VEC2 => |val| set_array(u32, val.*[0..], argv, types),
+ .BOOL_VEC3 => |val| set_array(u32, val.*[0..], argv, types),
+ .BOOL_VEC4 => |val| set_array(u32, val.*[0..], argv, types),
+ .FLOAT_MAT2 => |val| set_array(f32, val.*[0..], argv, types),
+ .FLOAT_MAT3 => |val| set_array(f32, val.*[0..], argv, types),
+ .FLOAT_MAT4 => |val| set_array(f32, val.*[0..], argv, types),
+ .FLOAT_MAT2x3 => |val| set_array(f32, val.*[0..], argv, types),
+ .FLOAT_MAT2x4 => |val| set_array(f32, val.*[0..], argv, types),
+ .FLOAT_MAT3x2 => |val| set_array(f32, val.*[0..], argv, types),
+ .FLOAT_MAT3x4 => |val| set_array(f32, val.*[0..], argv, types),
+ .FLOAT_MAT4x2 => |val| set_array(f32, val.*[0..], argv, types),
+ .FLOAT_MAT4x3 => |val| set_array(f32, val.*[0..], argv, types),
+ .DOUBLE_MAT2 => |val| set_array(f64, val.*[0..], argv, types),
+ .DOUBLE_MAT3 => |val| set_array(f64, val.*[0..], argv, types),
+ .DOUBLE_MAT4 => |val| set_array(f64, val.*[0..], argv, types),
+ .DOUBLE_MAT2x3 => |val| set_array(f64, val.*[0..], argv, types),
+ .DOUBLE_MAT2x4 => |val| set_array(f64, val.*[0..], argv, types),
+ .DOUBLE_MAT3x2 => |val| set_array(f64, val.*[0..], argv, types),
+ .DOUBLE_MAT3x4 => |val| set_array(f64, val.*[0..], argv, types),
+ .DOUBLE_MAT4x2 => |val| set_array(f64, val.*[0..], argv, types),
+ .DOUBLE_MAT4x3 => |val| set_array(f64, val.*[0..], argv, types),
.SAMPLER_2D,
.SAMPLER_2D_SHADOW,
.INT_SAMPLER_2D,
.UNSIGNED_INT_SAMPLER_2D,
- => |val| set_texture(self.progress, self.config.project_root, val, .TEXTURE_2D, argc, argv, types),
+ => |val| set_texture(self.progress, val, .TEXTURE_2D, argv, types),
.SAMPLER_2D_ARRAY,
.SAMPLER_2D_ARRAY_SHADOW,
.INT_SAMPLER_2D_ARRAY,
.UNSIGNED_INT_SAMPLER_2D_ARRAY,
- => |val| set_texture(self.progress, self.config.project_root, val, .TEXTURE_2D_ARRAY, argc, argv, types),
+ => |val| set_texture(self.progress, val, .TEXTURE_2D_ARRAY, argv, types),
.SAMPLER_3D,
.INT_SAMPLER_3D,
.UNSIGNED_INT_SAMPLER_3D,
- => |val| set_texture(self.progress, self.config.project_root, val, .TEXTURE_3D, argc, argv, types),
+ => |val| set_texture(self.progress, val, .TEXTURE_3D, argv, types),
else => error.uniformNotSupported,
};
@@ -279,29 +256,80 @@ pub const ControlServer = struct {
uniform.setShaderValue(self.cache.shader.*);
}
- fn handle_method(
+ fn handle_shader(
+ path: [*c]const u8,
+ types: [*c]const u8,
+ argv: [*c][*c]c.lo_arg,
+ argc: c_int,
+ msg: c.lo_message,
+ userdata: ?*anyopaque,
+ ) callconv(.C) c_int {
+ const self: *ControlServer = @ptrCast(@alignCast(userdata.?));
+ const code: [*:0]const u8 = @ptrCast(&argv[0].*.s);
+
+ _ = path;
+ _ = types;
+ _ = argc;
+ _ = msg;
+
+ _ = e: {
+ self.cache.shader.loadString(std.mem.span(code)) catch |err| break :e err;
+ self.cache.refresh() catch |err| break :e err;
+ } catch |err| {
+ std.debug.print("{} while loading shader from OSC\n", .{err});
+ };
+
+ return 0;
+ }
+
+ fn handle_reload(
+ path: [*c]const u8,
+ types: [*c]const u8,
+ argv: [*c][*c]c.lo_arg,
+ argc: c_int,
+ msg: c.lo_message,
+ userdata: ?*anyopaque,
+ ) callconv(.C) c_int {
+ const self: *ControlServer = @ptrCast(@alignCast(userdata.?));
+
+ _ = path;
+ _ = types;
+ _ = argc;
+ _ = argv;
+ _ = msg;
+
+ _ = e: {
+ self.cache.shader.loadFile(self.config.fragment, 2048) catch |err| break :e err;
+ self.cache.refresh() catch |err| break :e err;
+ } catch |err| {
+ std.debug.print("{} while reloading shader from file\n", .{err});
+ };
+
+ return 0;
+ }
+
+ fn handle_uniform(
_path: [*c]const u8,
_types: [*c]const u8,
- argv: [*c][*c]c.lo_arg,
+ _argv: [*c][*c]c.lo_arg,
argc: c_int,
msg: c.lo_message,
userdata: ?*anyopaque,
) callconv(.C) c_int {
_ = msg;
- const self = @as(*ControlServer, @ptrCast(@alignCast(userdata.?)));
+ const self: *ControlServer = @ptrCast(@alignCast(userdata.?));
const path = _path[0..c.strlen(_path)];
- const types = _types[0..@as(u32, @intCast(argc))];
+ const argv: [][*c]c.lo_arg = _argv[0..@intCast(argc)];
+ const types = _types[0..@intCast(argc)];
- if (std.mem.eql(u8, path, "/-/reload")) {
- self.reload_requested = true;
- return 1;
- }
-
- self.set_uniform(path, argv, argc, types) catch |err| {
- std.debug.print("{} while processing {s}\n", .{ err, path });
+ self.set_uniform(path, argv, types) catch |err| {
+ if (err != error.notFound) {
+ std.debug.print("{} while processing {s}\n", .{ err, path });
+ }
return 1;
};
+
return 0;
}
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,
diff --git a/src/main.zig b/src/main.zig
index 932fdca..11052e5 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -1,8 +1,6 @@
const std = @import("std");
-const fs = std.fs;
const debug = std.debug;
const panic = debug.panic;
-const process = std.process;
const c = @import("c.zig");
const debug_gl = @import("debug_gl.zig");
const cfg = @import("config.zig");
@@ -24,11 +22,7 @@ pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
- var args = process.args();
- _ = args.next();
-
- const filename = args.next() orelse "config.yaml";
- var config = try cfg.Config.parse(arena.allocator(), filename);
+ var config = try cfg.Config.init(arena.allocator());
_ = c.glfwSetErrorCallback(errorCallback);
@@ -111,9 +105,9 @@ pub fn main() !void {
var fbo = try gl.FramebufferObject.create(config.width, config.height);
defer fbo.destroy();
- const shader_file = try config.project_root.openFile(config.fragment, .{});
- var last_stat = try shader_file.stat();
- try reloadShader(&config, &main_program, config.fragment, last_stat.size);
+ // const shader_file = try std.fs.cwd().openFile(config.fragment, .{});
+ // var last_stat = try shader_file.stat();
+ // try main_program.loadFile(config.fragment, last_stat.size);
var cache = gl.UniformCache.init(std.heap.c_allocator, &main_program);
defer cache.deinit();
@@ -130,14 +124,14 @@ pub fn main() !void {
control.update();
- const stat = try shader_file.stat();
- if (stat.mtime > last_stat.mtime or control.reload_requested) {
- try reloadShader(&config, &main_program, config.fragment, stat.size);
- try cache.refresh();
- last_stat = stat;
-
- control.reload_requested = false;
- }
+ // const stat = try shader_file.stat();
+ // if (stat.mtime > last_stat.mtime or control.reload_requested) {
+ // try main_program.loadFile(config.fragment, stat.size);
+ // try cache.refresh();
+ // last_stat = stat;
+ //
+ // control.reload_requested = false;
+ // }
fbo.bind();
c.glClear(c.GL_COLOR_BUFFER_BIT);
@@ -161,103 +155,3 @@ pub fn main() !void {
c.glfwPollEvents();
}
}
-
-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 loadFile(config: *const cfg.Config, writer: anytype, dir: []const u8, filename: []const u8) !void {
- const file_dir = try fs.path.resolve(c_allocator, &[_][]const u8{
- dir,
- fs.path.dirname(filename) orelse "",
- });
- defer c_allocator.free(file_dir);
-
- const file_path = try fs.path.resolve(c_allocator, &[_][]const u8{ dir, filename });
- defer c_allocator.free(file_path);
-
- var file = try config.project_root.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] != '"') {
- debug.print("{s}:{}: Invalid #pragma include\n", .{ file_path, line_number });
- debug.print("{s}:{}: {s}\n", .{ file_path, line_number, line });
- continue;
- }
- include_path = include_path[1 .. include_path.len - 1];
-
- loadFile(config, writer, file_dir, include_path) catch unreachable;
- _ = try writer.print("#line {d} \"{s}\"\n", .{ line_number, escape_dquote(filename) });
-
- continue;
- } else {
- debug.print("{s}:{}: Unknown #pragma directive '{s}'\n", .{ file_path, line_number, pragma });
- 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;
- }
-}
-
-fn reloadShader(config: *const cfg.Config, current: *gl.ShaderProgram, frag_filename: []const u8, size: u64) !void {
- var buffer = try std.ArrayList(u8).initCapacity(c_allocator, @as(usize, @intCast(size)));
- errdefer buffer.deinit();
-
- const writer = buffer.writer();
- _ = try writer.write(
- \\#version 330 core
- \\#extension GL_ARB_shading_language_include : require
- \\
- );
- try loadFile(config, writer, "", frag_filename);
-
- const frag_source = try buffer.toOwnedSlice();
- defer c_allocator.free(frag_source);
-
- const vert_source =
- \\#version 330 core
- \\
- \\layout(location = 0) in vec2 position;
- \\out vec2 uv;
- \\
- \\void main() {
- \\ uv = position / 2.0 + 0.5;
- \\ gl_Position = vec4(position, 0, 1);
- \\}
- ;
-
- if (gl.ShaderProgram.create(vert_source, frag_source)) |new_program| {
- current.destroy();
- current.* = new_program;
- } else |err| {
- debug.print("Error while reloading shader: {}\n", .{err});
- }
-}
diff --git a/src/output.zig b/src/output.zig
index df219d2..b5c6885 100644
--- a/src/output.zig
+++ b/src/output.zig
@@ -2,7 +2,6 @@ const c = @import("c.zig");
const std = @import("std");
const cfg = @import("config.zig");
const gl = @import("gl.zig");
-const yaml = @import("yaml.zig");
pub const Output = struct {
update_fn: *const fn (output: *Output, texture_id: c.GLuint) bool,
@@ -35,38 +34,6 @@ pub const TSVOutput = struct {
pub const default: Config = .{
.name = "glsl-view",
};
-
- pub fn parse(parser: *c.yaml_parser_t, allocator: std.mem.Allocator) !Config {
- var self: Config = .default;
-
- while (true) {
- var event: c.yaml_event_t = undefined;
- if (c.yaml_parser_parse(parser, &event) != 1)
- return error.YAMLParserError;
- defer c.yaml_event_delete(&event);
-
- switch (event.type) {
- c.YAML_MAPPING_END_EVENT => break,
- c.YAML_SCALAR_EVENT => {
- const data = event.data.scalar;
- const key: []const u8 = data.value[0..data.length];
-
- if (std.mem.eql(u8, key, "name")) {
- self.name = try yaml.parseStringZ(parser, allocator);
- } else {
- std.debug.print("unknown key: '{s}'\n", .{key});
- try yaml.skipAny(parser);
- }
- },
- else => {
- std.debug.print("unexpected event: {}\n", .{event.type});
- return error.InvalidConfiguration;
- },
- }
- }
-
- return self;
- }
};
output: Output,
@@ -154,46 +121,6 @@ pub const WindowOutput = struct {
.monitor = "",
.fullscreen = false,
};
-
- pub fn parse(parser: *c.yaml_parser_t, allocator: std.mem.Allocator) !Config {
- var self: Config = .default;
-
- while (true) {
- var event: c.yaml_event_t = undefined;
- if (c.yaml_parser_parse(parser, &event) != 1)
- return error.YAMLParserError;
- defer c.yaml_event_delete(&event);
-
- switch (event.type) {
- c.YAML_MAPPING_END_EVENT => break,
- c.YAML_SCALAR_EVENT => {
- const data = event.data.scalar;
- const key: []const u8 = data.value[0..data.length];
-
- if (std.mem.eql(u8, key, "width")) {
- self.width = try yaml.parseInt(parser, i32);
- } else if (std.mem.eql(u8, key, "height")) {
- self.height = try yaml.parseInt(parser, i32);
- } else if (std.mem.eql(u8, key, "filter")) {
- self.filter = try yaml.parseEnum(parser, FilterMode);
- } else if (std.mem.eql(u8, key, "monitor")) {
- self.monitor = try yaml.parseString(parser, allocator);
- } else if (std.mem.eql(u8, key, "fullscreen")) {
- self.fullscreen = try yaml.parseBool(parser);
- } else {
- std.debug.print("unknown key: '{s}'\n", .{key});
- try yaml.skipAny(parser);
- }
- },
- else => {
- std.debug.print("unexpected event: {}\n", .{event.type});
- return error.InvalidConfiguration;
- },
- }
- }
-
- return self;
- }
};
output: Output,