forked from mirrors/zig-glsl-view
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
7.7 KiB
Zig
193 lines
7.7 KiB
Zig
const c = @import("c.zig");
|
|
const gl = @import("gl.zig");
|
|
const std = @import("std");
|
|
const cfg = @import("config.zig");
|
|
|
|
fn verify_args(expected: u8, got: []const u8) !void {
|
|
for (got) |typ| {
|
|
if (typ != expected) {
|
|
std.debug.print("expected '{c}' but got '{c}' element (expected {s})\n", .{ expected, typ, got });
|
|
return error.typeMismatch;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn set_array(comptime T: type, dest: []T, argc: c_int, argv: [*c][*c]c.lo_arg, types: []const u8) !void {
|
|
if (argc != dest.len)
|
|
return error.sizeMismatch;
|
|
|
|
switch (T) {
|
|
f32 => {
|
|
try verify_args('f', types);
|
|
for (dest) |*v, i|
|
|
v.* = argv[i].*.f;
|
|
},
|
|
f64 => {
|
|
try verify_args('d', types);
|
|
for (dest) |*v, i|
|
|
v.* = argv[i].*.d;
|
|
},
|
|
i32 => {
|
|
try verify_args('i', types);
|
|
for (dest) |*v, i|
|
|
v.* = argv[i].*.i;
|
|
},
|
|
u32 => {
|
|
try verify_args('i', types);
|
|
for (dest) |*v, i| {
|
|
const val = argv[i].*.i;
|
|
if (val < 0)
|
|
return error.signDisallowed;
|
|
v.* = @intCast(u32, argv[i].*.i);
|
|
}
|
|
},
|
|
else => return error.invalidType,
|
|
}
|
|
}
|
|
|
|
pub const ControlServer = struct {
|
|
server: c.lo_server,
|
|
cache: *gl.UniformCache,
|
|
|
|
pub fn init(
|
|
allocator: std.mem.Allocator,
|
|
config: cfg.OSCConfig,
|
|
cache: *gl.UniformCache,
|
|
) !*ControlServer {
|
|
var self: *ControlServer = try allocator.create(ControlServer);
|
|
self.cache = cache;
|
|
|
|
switch (config) {
|
|
.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);
|
|
},
|
|
}
|
|
|
|
if (self.server == null)
|
|
return error.serverInitializationError;
|
|
_ = c.lo_server_add_method(self.server, null, null, handle_method, @ptrCast(*anyopaque, self));
|
|
|
|
return self;
|
|
}
|
|
|
|
pub fn update(self: *ControlServer) void {
|
|
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.print(
|
|
"OSC error {} @ {s}: {s}\n",
|
|
.{ num, @ptrCast([*:0]const u8, where), @ptrCast([*:0]const u8, msg) },
|
|
);
|
|
}
|
|
|
|
fn set_uniform(
|
|
self: *ControlServer,
|
|
uniform_name: []const u8,
|
|
argv: [*c][*c]c.lo_arg,
|
|
argc: c_int,
|
|
types: []const u8,
|
|
) !void {
|
|
var buffer: [256]u8 = undefined;
|
|
std.mem.copy(u8, buffer[0..], uniform_name);
|
|
buffer[uniform_name.len] = 0;
|
|
const name = buffer[0..uniform_name.len :0];
|
|
const uniform = (try self.cache.get(name)) orelse return error.notFound;
|
|
|
|
try switch (uniform.value) {
|
|
.FLOAT => |*val| set_array(f32, @ptrCast([*]f32, val)[0..1], argc, argv, types),
|
|
.DOUBLE => |*val| set_array(f64, @ptrCast([*]f64, val)[0..1], argc, argv, types),
|
|
.INT => |*val| set_array(i32, @ptrCast([*]i32, val)[0..1], argc, argv, types),
|
|
.UNSIGNED_INT => |*val| set_array(u32, @ptrCast([*]u32, val)[0..1], argc, argv, types),
|
|
.BOOL => |*val| set_array(u32, @ptrCast([*]u32, val)[0..1], 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),
|
|
else => error.uniformNotSupported,
|
|
};
|
|
|
|
uniform.setShaderValue(self.cache.shader.*);
|
|
}
|
|
|
|
fn handle_method(
|
|
_path: [*c]const u8,
|
|
_types: [*c]const u8,
|
|
argv: [*c][*c]c.lo_arg,
|
|
argc: c_int,
|
|
_: c.lo_message,
|
|
userdata: ?*anyopaque,
|
|
) callconv(.C) c_int {
|
|
const self = @ptrCast(*ControlServer, @alignCast(@alignOf(ControlServer), userdata.?));
|
|
const path = _path[0..c.strlen(_path) :0];
|
|
const types = _types[0..@intCast(u32, argc)];
|
|
|
|
if (!std.mem.startsWith(u8, path, "/")) {
|
|
std.debug.print("invalid OSC message {s} ({s})\n", .{ path, types });
|
|
return 1;
|
|
}
|
|
|
|
self.set_uniform(path[1..], argv, argc, types) catch |err| {
|
|
std.debug.print("{} while processing {s}\n", .{ err, path });
|
|
};
|
|
return 0;
|
|
}
|
|
|
|
fn handle_bundle_start(_: c.lo_timetag, _: ?*anyopaque) callconv(.C) c_int {
|
|
return 1;
|
|
}
|
|
|
|
fn handle_bundle_end(_: ?*anyopaque) callconv(.C) c_int {
|
|
return 1;
|
|
}
|
|
};
|