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, &.{ "/source", name, "freeze" }, "T", handle_freeze) catch unreachable; control.add_method_for(StreamFlags, self, &.{ "/source", name, "freeze" }, "F", handle_freeze) catch unreachable; control.add_method_for(StreamFlags, self, &.{ "/source", name, "step" }, "I", handle_step) catch unreachable; control.add_method_for(StreamFlags, self, &.{ "/source", name, "step" }, "", handle_step) catch unreachable; } pub fn unregister(self: *const StreamFlags, name: []const u8, control: *ctrl.ControlServer) void { _ = self; control.del_method(&.{ "/source", name, "freeze" }, "T") catch unreachable; control.del_method(&.{ "/source", name, "freeze" }, "F") catch unreachable; control.del_method(&.{ "/source", 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; } };