diff options
| author | s-ol <s+removethis@s-ol.nu> | 2025-08-05 00:48:42 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-08-05 01:06:20 +0000 |
| commit | 57f37fbd6a4816f3a70041e04877beeb0a37b45c (patch) | |
| tree | bd054c31e2a3b8705197f85705484bda4fe56698 /src | |
| parent | add freeze and step controls to Source (diff) | |
| download | glsl-view-57f37fbd6a4816f3a70041e04877beeb0a37b45c.tar.gz glsl-view-57f37fbd6a4816f3a70041e04877beeb0a37b45c.zip | |
dynamic OSC method registration for sources
Diffstat (limited to 'src')
| -rw-r--r-- | src/control.zig | 202 | ||||
| -rw-r--r-- | src/ffmpeg.zig | 31 | ||||
| -rw-r--r-- | src/gl.zig | 42 | ||||
| -rw-r--r-- | src/source.zig | 72 | ||||
| -rw-r--r-- | src/tsv.zig | 15 | ||||
| -rw-r--r-- | src/util.zig | 21 |
6 files changed, 225 insertions, 158 deletions
diff --git a/src/control.zig b/src/control.zig index 4f4d547..71e688a 100644 --- a/src/control.zig +++ b/src/control.zig @@ -1,7 +1,9 @@ +const std = @import("std"); const c = @import("c.zig"); const gl = @import("gl.zig"); -const std = @import("std"); +const src = @import("source.zig"); const cfg = @import("config.zig"); +const util = @import("util.zig"); const build_config = @import("build_config"); fn verify_args(expected: u8, got: []const u8) !void { @@ -84,26 +86,9 @@ fn set_array( } } -fn set_texture( - cache: *gl.UniformCache, - dest: *?*gl.Texture, - texture_type: gl.Texture.Type, - types: []const u8, - argv: []const [*c]c.lo_arg, -) !void { - if (types.len != 1 or types[0] != 's') return error.invalidType; - - const nameZ: [*:0]const u8 = @ptrCast(&argv[0].*.s); - const name = std.mem.span(nameZ); - - const source = cache.textures.get(name) orelse return error.texNotFound; - if (source.texture.type != texture_type) return error.wrongTextureType; - - dest.* = &source.texture; -} - pub const ControlServer = struct { server: c.lo_server, + sources: std.StringHashMap(*src.Source), cache: *gl.UniformCache, config: *cfg.Config, @@ -111,34 +96,6 @@ pub const ControlServer = struct { progress: std.Progress.Node, allocator: std.mem.Allocator, - const ZigCallback = fn (*ControlServer, []const u8, []const u8, []const [*c]c.lo_arg) anyerror!bool; - const CCallback = fn ([*c]const u8, [*c]const u8, [*c][*c]c.lo_arg, c_int, c.lo_message, ?*anyopaque) callconv(.C) c_int; - fn wrapCallback(comptime inner: ZigCallback) CCallback { - return struct { - fn wrapped( - _path: ?[*:0]const u8, - _types: ?[*:0]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 path = std.mem.span(_path.?); - const types = std.mem.span(_types.?); - const args = if (_argv) |argv| argv[0..@intCast(argc)] else &.{}; - - _ = msg; - - const res = inner(self, path, types, args) catch |err| { - std.debug.print("Error handling {s}: {}\n", .{ path, err }); - return 1; - }; - return if (res) 0 else 1; - } - }.wrapped; - } - pub fn init( allocator: std.mem.Allocator, progress: std.Progress.Node, @@ -149,6 +106,7 @@ pub const ControlServer = struct { var self: *ControlServer = try allocator.create(ControlServer); self.* = .{ .server = null, + .sources = std.StringHashMap(*src.Source).init(cache.allocator), .cache = cache, .config = config, @@ -164,31 +122,74 @@ pub const ControlServer = struct { if (self.server == null) return error.serverInitializationError; - _ = c.lo_server_add_method(self.server, "/shader", "s", wrapCallback(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, "/uniform/*", null, wrapCallback(handle_uniform), @as(*anyopaque, @ptrCast(self))); + try self.add_method(&.{ "", "shader" }, "s", handle_shader); + // try self.add_method(&.{ "", "reload" }, "", handle_reload); + try self.add_method(&.{ "", "uniform", "*" }, null, handle_uniform); if (build_config.have_ffmpeg) { - _ = c.lo_server_add_method(self.server, "/texture/*/video", null, wrapCallback(handle_texture_video), @as(*anyopaque, @ptrCast(self))); - _ = c.lo_server_add_method(self.server, "/texture/*/stream", null, wrapCallback(handle_texture_stream), @as(*anyopaque, @ptrCast(self))); + try self.add_method(&.{ "", "texture", "*", "video" }, null, handle_texture_video); + try self.add_method(&.{ "", "texture", "*", "stream" }, null, handle_texture_stream); } if (build_config.have_tsv) { - _ = c.lo_server_add_method(self.server, "/texture/*/tsv", "ss", wrapCallback(handle_texture_tsv), @as(*anyopaque, @ptrCast(self))); + try self.add_method(&.{ "", "texture", "*", "tsv" }, "ss", handle_texture_tsv); } - _ = c.lo_server_add_method(self.server, "/texture/*/freeze", "T", wrapCallback(handle_texture_freeze), @as(*anyopaque, @ptrCast(self))); - _ = c.lo_server_add_method(self.server, "/texture/*/freeze", "F", wrapCallback(handle_texture_freeze), @as(*anyopaque, @ptrCast(self))); - _ = c.lo_server_add_method(self.server, "/texture/*/step", "", wrapCallback(handle_texture_step), @as(*anyopaque, @ptrCast(self))); - _ = c.lo_server_add_method(self.server, "/texture/*/destroy", "", wrapCallback(handle_destroy_texture), @as(*anyopaque, @ptrCast(self))); + try self.add_method(&.{ "", "texture", "*", "destroy" }, "", handle_destroy_texture); return self; } + fn add_method(self: *ControlServer, pieces: []const []const u8, types: ?[]const u8, handler: anytype) !void { + try self.add_method_for(ControlServer, self, pieces, types, handler); + } + + pub fn add_method_for(self: *ControlServer, comptime Self: type, data: *Self, pieces: []const []const u8, types: ?[]const u8, handler: anytype) !void { + const path = try util.tmpJoinZ("/", pieces); + + const wrapped = struct { + fn wrapped( + _path: ?[*:0]const u8, + _types: ?[*:0]const u8, + _argv: [*c][*c]c.lo_arg, + argc: c_int, + msg: c.lo_message, + userdata: ?*anyopaque, + ) callconv(.C) c_int { + const i_self: *Self = @ptrCast(@alignCast(userdata.?)); + const i_path = std.mem.span(_path.?); + const i_types = std.mem.span(_types.?); + const args = if (_argv) |argv| argv[0..@intCast(argc)] else &.{}; + + _ = msg; + + const res = handler(i_self, i_path, i_types, args) catch |err| { + std.debug.print("Error handling {s}: {}\n", .{ i_path, err }); + return 1; + }; + return if (res) 0 else 1; + } + }.wrapped; + + _ = c.lo_server_add_method(self.server, path, if (types) |t| t.ptr else null, wrapped, @as(*anyopaque, @ptrCast(data))); + } + + pub fn del_method(self: *ControlServer, pieces: []const []const u8, types: ?[]const u8) !void { + const path = try util.tmpJoinZ("/", pieces); + _ = c.lo_server_del_method(self.server, path, if (types) |t| t.ptr else null); + } + pub fn update(self: *ControlServer) void { while (c.lo_server_recv_noblock(self.server, 0) > 0) {} } - pub fn destroy(self: ControlServer) void { + pub fn destroy(self: *ControlServer) void { c.lo_server_free(self.server); + + var tit = self.sources.iterator(); + while (tit.next()) |entry| { + entry.value_ptr.*.deinit(self.allocator); + self.allocator.free(entry.key_ptr.*); + } + self.sources.deinit(); } fn handle_error(num: c_int, msg: [*c]const u8, where: [*c]const u8) callconv(.C) void { @@ -219,6 +220,24 @@ pub const ControlServer = struct { return true; } + fn set_texture( + self: *ControlServer, + dest: *?*gl.Texture, + texture_type: gl.Texture.Type, + types: []const u8, + argv: []const [*c]c.lo_arg, + ) !void { + if (types.len != 1 or types[0] != 's') return error.invalidType; + + const nameZ: [*:0]const u8 = @ptrCast(&argv[0].*.s); + const name = std.mem.span(nameZ); + + const source = self.sources.get(name) orelse return error.texNotFound; + if (source.texture.type != texture_type) return error.wrongTextureType; + + dest.* = &source.texture; + } + fn handle_uniform(self: *ControlServer, path: []const u8, types: []const u8, argv: []const [*c]c.lo_arg) !bool { var parts = std.mem.tokenizeScalar(u8, path, '/'); @@ -292,18 +311,18 @@ pub const ControlServer = struct { .SAMPLER_2D_SHADOW, .INT_SAMPLER_2D, .UNSIGNED_INT_SAMPLER_2D, - => |val| set_texture(self.cache, val, .TEXTURE_2D, types, argv), + => |val| self.set_texture(val, .TEXTURE_2D, types, argv), .SAMPLER_2D_ARRAY, .SAMPLER_2D_ARRAY_SHADOW, .INT_SAMPLER_2D_ARRAY, .UNSIGNED_INT_SAMPLER_2D_ARRAY, - => |val| set_texture(self.cache, val, .TEXTURE_2D_ARRAY, types, argv), + => |val| self.set_texture(val, .TEXTURE_2D_ARRAY, types, argv), .SAMPLER_3D, .INT_SAMPLER_3D, .UNSIGNED_INT_SAMPLER_3D, - => |val| set_texture(self.cache, val, .TEXTURE_3D, types, argv), + => |val| self.set_texture(val, .TEXTURE_3D, types, argv), else => error.uniformNotSupported, }; @@ -312,13 +331,21 @@ pub const ControlServer = struct { return true; } + fn add_source(self: *ControlServer, name: []const u8, source: *src.Source) !void { + const key = try self.cache.allocator.dupe(u8, name); + errdefer self.cache.allocator.free(key); + try self.sources.put(key, source); + + source.register(name, self); + } + fn handle_texture_video(self: *ControlServer, path: []const u8, types: []const u8, argv: []const [*c]c.lo_arg) !bool { try verify_args('s', types); var parts = std.mem.tokenizeScalar(u8, path, '/'); _ = parts.next(); const name = parts.next() orelse unreachable; - if (self.cache.textures.contains(name)) return error.textureNameTaken; + if (self.sources.contains(name)) return error.textureNameTaken; const texture_typeZ: [*:0]const u8 = @ptrCast(&argv[0].*.s); const texture_type = std.meta.stringToEnum(gl.Texture.Type, std.mem.span(texture_typeZ)) orelse return error.invalidType; @@ -328,10 +355,7 @@ pub const ControlServer = struct { const ffmpeg = @import("ffmpeg.zig"); const source = try ffmpeg.VideoSource.init(self.cache.allocator, self.progress, texture_type, filenameZ, formatZ, args); - - const key = try self.cache.allocator.dupe(u8, name); - errdefer self.cache.allocator.free(key); - try self.cache.textures.put(key, source); + try self.add_source(name, source); return true; } @@ -342,7 +366,7 @@ pub const ControlServer = struct { var parts = std.mem.tokenizeScalar(u8, path, '/'); _ = parts.next(); const name = parts.next() orelse unreachable; - if (self.cache.textures.contains(name)) return error.textureNameTaken; + if (self.sources.contains(name)) return error.textureNameTaken; const texture_typeZ: [*:0]const u8 = @ptrCast(&argv[0].*.s); const filenameZ: [*:0]const u8 = @ptrCast(&argv[1].*.s); @@ -353,10 +377,7 @@ pub const ControlServer = struct { const ffmpeg = @import("ffmpeg.zig"); const source = try ffmpeg.StreamSource.init(self.cache.allocator, self.constants, filenameZ, formatZ, args); - - const key = try self.cache.allocator.dupe(u8, name); - errdefer self.cache.allocator.free(key); - try self.cache.textures.put(key, source); + try self.add_source(name, source); return true; } @@ -367,7 +388,7 @@ pub const ControlServer = struct { var parts = std.mem.tokenizeScalar(u8, path, '/'); _ = parts.next(); const name = parts.next() orelse unreachable; - if (self.cache.textures.contains(name)) return error.textureNameTaken; + if (self.sources.contains(name)) return error.textureNameTaken; const texture_typeZ: [*:0]const u8 = @ptrCast(&argv[0].*.s); const texture_type = std.meta.stringToEnum(gl.Texture.Type, std.mem.span(texture_typeZ)) orelse return error.invalidType; @@ -375,39 +396,7 @@ pub const ControlServer = struct { const tsv = @import("tsv.zig"); const source = try tsv.TSVSource.init(self.cache.allocator, self.constants, texture_type, tsv_nameZ); - - const key = try self.cache.allocator.dupe(u8, name); - errdefer self.cache.allocator.free(key); - try self.cache.textures.put(key, source); - - return true; - } - - fn handle_texture_freeze(self: *ControlServer, path: []const u8, types: []const u8, argv: []const [*c]c.lo_arg) !bool { - _ = argv; - - var parts = std.mem.tokenizeScalar(u8, path, '/'); - _ = parts.next(); - const name = parts.next() orelse unreachable; - - if (self.cache.textures.get(name)) |source| { - source.freeze = types[0] == 'T'; - } else return false; - - return true; - } - - fn handle_texture_step(self: *ControlServer, path: []const u8, types: []const u8, argv: []const [*c]c.lo_arg) !bool { - _ = argv; - _ = types; - - var parts = std.mem.tokenizeScalar(u8, path, '/'); - _ = parts.next(); - const name = parts.next() orelse unreachable; - - if (self.cache.textures.get(name)) |source| { - source.step.store(true, .monotonic); - } else return false; + try self.add_source(name, source); return true; } @@ -420,8 +409,9 @@ pub const ControlServer = struct { _ = parts.next(); const name = parts.next() orelse unreachable; - if (self.cache.textures.fetchRemove(name)) |kv| { + if (self.sources.fetchRemove(name)) |kv| { // @TODO: find all references to kv.value.texture in UniformCache and unassign + kv.value.unregister(name, self); kv.value.deinit(self.cache.allocator); self.cache.allocator.free(kv.key); } else return false; diff --git a/src/ffmpeg.zig b/src/ffmpeg.zig index dda3f8c..700638f 100644 --- a/src/ffmpeg.zig +++ b/src/ffmpeg.zig @@ -1,6 +1,8 @@ const std = @import("std"); const c = @import("c.zig"); const gl = @import("gl.zig"); +const src = @import("source.zig"); +const ctrl = @import("control.zig"); const build_config = @import("build_config"); pub const Errors = error{ @@ -248,7 +250,7 @@ pub const AVDecoder = struct { }; pub const VideoSource = struct { - source: gl.Source, + source: src.Source, decoder: *Decoder, pub fn init( @@ -258,7 +260,7 @@ pub const VideoSource = struct { filename: [*:0]const u8, format_name: ?[*:0]const u8, format_options: []const [*c]c.lo_arg, - ) !*gl.Source { + ) !*src.Source { const self = try allocator.create(VideoSource); errdefer allocator.destroy(self); @@ -293,12 +295,13 @@ pub const VideoSource = struct { else try AVDecoder.init(allocator, codec_par), }; + errdefer self.decoder.deinit(allocator); self.source.texture = try self.decoder.createTexture(progress, format, video_stream, texture_type); return &self.source; } - fn deinit(source: *const gl.Source, allocator: std.mem.Allocator) void { + fn deinit(source: *const src.Source, allocator: std.mem.Allocator) void { const self: *const VideoSource = @fieldParentPtr("source", source); self.decoder.deinit(allocator); @@ -307,7 +310,8 @@ pub const VideoSource = struct { }; pub const StreamSource = struct { - source: gl.Source, + source: src.Source, + flags: src.StreamFlags, decoder: *Decoder, format: *c.AVFormatContext, @@ -322,7 +326,7 @@ pub const StreamSource = struct { filename: [*:0]const u8, format_name: ?[*:0]const u8, format_options: []const [*c]c.lo_arg, - ) !*gl.Source { + ) !*src.Source { const self = try allocator.create(StreamSource); errdefer allocator.destroy(self); @@ -351,12 +355,16 @@ pub const StreamSource = struct { ); const decoder = try AVDecoder.init(allocator, codec_par); + errdefer decoder.deinit(allocator); self.* = .{ .source = .{ .texture = texture, .deinit_fn = deinit, + .register_fn = register_methods, + .unregister_fn = unregister_methods, }, + .flags = .{}, .decoder = decoder, .format = format, @@ -372,6 +380,15 @@ pub const StreamSource = struct { return &self.source; } + fn register_methods(source: *src.Source, name: []const u8, control: *ctrl.ControlServer) void { + const self: *StreamSource = @fieldParentPtr("source", source); + self.flags.register(name, control); + } + fn unregister_methods(source: *src.Source, name: []const u8, control: *ctrl.ControlServer) void { + const self: *StreamSource = @fieldParentPtr("source", source); + self.flags.unregister(name, control); + } + fn update_loop(self: *StreamSource) !void { while (!self.thread.quit) { try self.update(); @@ -390,11 +407,11 @@ pub const StreamSource = struct { _ = try self.decoder.process_packet_fn( self.decoder, self.packet, - if (self.source.shouldStep()) &self.source.texture else null, + if (self.flags.shouldStep()) &self.source.texture else null, ); } - fn deinit(source: *gl.Source, allocator: std.mem.Allocator) void { + fn deinit(source: *src.Source, allocator: std.mem.Allocator) void { const self: *StreamSource = @fieldParentPtr("source", source); self.thread.deinit(allocator); @@ -2,13 +2,7 @@ const std = @import("std"); const c_allocator = @import("std").heap.c_allocator; const c = @import("c.zig"); const cfg = @import("config.zig"); - -fn tmpZ(str: []const u8) ![:0]const u8 { - const state = struct { - var buf: [256]u8 = undefined; - }; - return try std.fmt.bufPrintZ(state.buf[0..], "{s}", .{str}); -} +const util = @import("util.zig"); var image_unit_map = [_]bool{false} ** 1024; @@ -502,7 +496,7 @@ pub const CachedUniform = struct { ) !CachedUniform { var index: c.GLuint = undefined; - const nameZ = try tmpZ(name); + const nameZ = try util.tmpZ(name); c.glGetUniformIndices(shader.program_id, 1, &nameZ.ptr, &index); if (index == c.GL_INVALID_INDEX) @@ -934,40 +928,15 @@ pub const Thread = struct { } }; -pub const Source = struct { - pub const Type = enum { - file, - texture_share_vk, - }; - - texture: Texture, - freeze: bool = false, - step: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), - - deinit_fn: *const fn (self: *Source, allocator: std.mem.Allocator) void, - - pub fn deinit(self: *Source, allocator: std.mem.Allocator) void { - self.deinit_fn(self, allocator); - } - - pub fn shouldStep(self: *Source) bool { - const step = !self.freeze or self.step.load(.acquire); - if (step) self.step.store(false, .release); - return step; - } -}; - pub const UniformCache = struct { allocator: std.mem.Allocator, uniforms: std.StringHashMap(CachedUniform), - textures: std.StringHashMap(*Source), shader: *ShaderProgram, pub fn init(allocator: std.mem.Allocator, shader: *ShaderProgram) UniformCache { return UniformCache{ .allocator = allocator, .uniforms = std.StringHashMap(CachedUniform).init(allocator), - .textures = std.StringHashMap(*Source).init(allocator), .shader = shader, }; } @@ -979,14 +948,7 @@ pub const UniformCache = struct { self.allocator.free(entry.key_ptr.*); } - var tit = self.textures.iterator(); - while (tit.next()) |entry| { - entry.value_ptr.*.deinit(self.allocator); - self.allocator.free(entry.key_ptr.*); - } - self.uniforms.deinit(); - self.textures.deinit(); } pub fn get(self: *UniformCache, name: []const u8) !?*CachedUniform { diff --git a/src/source.zig b/src/source.zig new file mode 100644 index 0000000..26a92a3 --- /dev/null +++ b/src/source.zig @@ -0,0 +1,72 @@ +const std = @import("std"); +const c = @import("c.zig"); +const gl = @import("gl.zig"); +const ctrl = @import("control.zig"); +const util = @import("util.zig"); + +pub const Source = struct { + texture: gl.Texture, + deinit_fn: *const fn (self: *Source, allocator: std.mem.Allocator) void, + register_fn: ?*const fn (self: *Source, name: []const u8, control: *ctrl.ControlServer) void = null, + unregister_fn: ?*const fn (self: *Source, name: []const u8, control: *ctrl.ControlServer) void = null, + + pub fn deinit(self: *Source, allocator: std.mem.Allocator) void { + self.deinit_fn(self, allocator); + } + + pub fn register(self: *Source, name: []const u8, control: *ctrl.ControlServer) void { + if (self.register_fn) |register_fn| { + register_fn(self, name, control); + } + } + + pub fn unregister(self: *Source, name: []const u8, control: *ctrl.ControlServer) void { + if (self.unregister_fn) |unregister_fn| { + unregister_fn(self, name, control); + } + } +}; + +pub const StreamFlags = struct { + freeze: bool = false, + step: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), + + pub fn register(self: *StreamFlags, name: []const u8, control: *ctrl.ControlServer) void { + control.add_method_for(StreamFlags, self, &.{ "", "texture", name, "freeze" }, "T", handle_freeze) catch unreachable; + control.add_method_for(StreamFlags, self, &.{ "", "texture", name, "freeze" }, "F", handle_freeze) catch unreachable; + control.add_method_for(StreamFlags, self, &.{ "", "texture", name, "step" }, "", handle_step) catch unreachable; + } + + pub fn unregister(self: *const StreamFlags, name: []const u8, control: *ctrl.ControlServer) void { + _ = self; + + control.del_method(&.{ "", "texture", name, "freeze" }, "T") catch unreachable; + control.del_method(&.{ "", "texture", name, "freeze" }, "F") catch unreachable; + control.del_method(&.{ "", "texture", name, "step" }, "") catch unreachable; + } + + pub fn shouldStep(self: *StreamFlags) bool { + const step = !self.freeze or self.step.load(.acquire); + if (step) self.step.store(false, .release); + return step; + } + + fn handle_freeze(self: *StreamFlags, path: []const u8, types: []const u8, argv: []const [*c]c.lo_arg) !bool { + _ = path; + _ = argv; + + self.freeze = types[0] == 'T'; + + return true; + } + + fn handle_step(self: *StreamFlags, path: []const u8, types: []const u8, argv: []const [*c]c.lo_arg) !bool { + _ = path; + _ = types; + _ = argv; + + self.step.store(true, .monotonic); + + return true; + } +}; diff --git a/src/tsv.zig b/src/tsv.zig index a723a52..7a121d7 100644 --- a/src/tsv.zig +++ b/src/tsv.zig @@ -1,7 +1,8 @@ const std = @import("std"); const c = @import("c.zig"); const gl = @import("gl.zig"); -const Source = gl.Source; +const src = @import("source.zig"); +const ctrl = @import("control.zig"); const Output = @import("output.zig").Output; var global_client: ?*c.GlClient = null; @@ -28,7 +29,9 @@ fn get_or_init_client() *c.GlClient { } pub const TSVSource = struct { - source: gl.Source, + source: src.Source, + stream: src.StreamFlags, + name: [:0]const u8, thread: *gl.Thread, @@ -37,7 +40,7 @@ pub const TSVSource = struct { constants: *const gl.Constants, texture_type: gl.Texture.Type, name: [*:0]const u8, - ) !*gl.Source { + ) !*src.Source { const self = try allocator.create(TSVSource); errdefer allocator.destroy(self); @@ -46,6 +49,8 @@ pub const TSVSource = struct { .texture = gl.Texture.create(texture_type), .deinit_fn = deinit, }, + .stream = .{}, + .name = try allocator.dupeZ(u8, std.mem.span(name)), .thread = undefined, }; @@ -68,7 +73,7 @@ pub const TSVSource = struct { return &self.source; } - fn deinit(source: *const gl.Source, allocator: std.mem.Allocator) void { + fn deinit(source: *const src.Source, allocator: std.mem.Allocator) void { const self: *const TSVSource = @fieldParentPtr("source", source); self.thread.deinit(allocator); @@ -85,7 +90,7 @@ pub const TSVSource = struct { } fn update(self: *TSVSource) void { - if (!self.source.shouldStep()) return; + if (!self.stream.shouldStep()) return; _ = c.gl_client_recv_image( get_or_init_client(), self.name.ptr, diff --git a/src/util.zig b/src/util.zig new file mode 100644 index 0000000..e168326 --- /dev/null +++ b/src/util.zig @@ -0,0 +1,21 @@ +const std = @import("std"); + +const state = struct { + var buf: [256]u8 = undefined; +}; +var fba = std.heap.FixedBufferAllocator.init(state.buf[0..]); + +pub fn tmpZ(str: []const u8) ![:0]const u8 { + fba.reset(); + return try std.fmt.allocPrintZ(fba.allocator(), "{s}", .{str}); +} + +pub fn tmpFmtZ(comptime fmt: []const u8, args: anytype) ![:0]const u8 { + fba.reset(); + return try std.fmt.allocPrintZ(fba.allocator(), fmt, args); +} + +pub fn tmpJoinZ(separator: []const u8, slices: []const []const u8) ![:0]const u8 { + fba.reset(); + return try std.mem.joinZ(fba.allocator(), separator, slices); +} |
