aboutsummaryrefslogtreecommitdiffstats
path: root/src/source.zig
blob: 6a3781ca625e64e3cb2b08573302168f167069ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
const std = @import("std");
const c = @import("c.zig").c;
const gl = @import("gl.zig");
const ctrl = @import("control.zig");
const util = @import("util.zig");

pub const Source = struct {
    texture: gl.Texture,
    update_fn: ?*const fn (self: *Source) anyerror!bool = null,
    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,
    update_uniform_fn: ?*const fn (self: *Source, param: []const u8, value: gl.UniformPointer) anyerror!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 fn update(self: *Source) bool {
        if (self.update_fn) |update_fn| {
            return update_fn(self) catch return true;
        }

        return false;
    }

    pub fn updateUniform(self: *Source, param: []const u8, value: gl.UniformPointer) anyerror!void {
        if (self.update_uniform_fn) |update_uniform_fn| {
            try update_uniform_fn(self, param, value);
        }
    }
};

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;
    }
};