aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2025-03-10 17:28:29 +0000
committers-ol <s+removethis@s-ol.nu>2025-03-15 13:05:19 +0000
commit7a7e0909fd016b95f70448f227c251a5a7da8423 (patch)
treed68ae85cee257205d710f281077dbb9e73107a10 /src
parentfix conditional compilation (diff)
downloadglsl-view-7a7e0909fd016b95f70448f227c251a5a7da8423.tar.gz
glsl-view-7a7e0909fd016b95f70448f227c251a5a7da8423.zip
texture-share-vk output support
Diffstat (limited to 'src')
-rw-r--r--src/c.zig5
-rw-r--r--src/config.zig317
-rw-r--r--src/main.zig10
-rw-r--r--src/output.zig203
-rw-r--r--src/yaml.zig127
5 files changed, 423 insertions, 239 deletions
diff --git a/src/c.zig b/src/c.zig
index 54c156e..fd837a3 100644
--- a/src/c.zig
+++ b/src/c.zig
@@ -15,4 +15,9 @@ pub usingnamespace @cImport({
if (build_config.have_hap) {
@cInclude("hap.h");
}
+
+ if (build_config.have_tsv) {
+ @cInclude("texture_share_gl/texture_share_gl_client.h");
+ @cInclude("texture_share_vk/config.hpp");
+ }
});
diff --git a/src/config.zig b/src/config.zig
index f8613bd..f1f65f9 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -2,25 +2,13 @@ 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");
+const build_config = @import("build_config");
-pub const OutputConfig = struct {
- const Type = enum {
- window,
- };
-
- const FilterMode = enum(c.GLuint) {
- nearest = c.GL_NEAREST,
- linear = c.GL_LINEAR,
- };
-
- type: Type,
- width: i32,
- height: i32,
- filter: FilterMode,
-
- // only for 'window'
- monitor: []const u8,
- fullscreen: bool,
+pub const OutputConfig = union(enum) {
+ window: out.WindowOutput.Config,
+ texture_share_vk: if (build_config.have_tsv) out.TSVOutput.Config else void,
};
pub const ParameterConfig = struct {
@@ -42,14 +30,7 @@ pub const OSCConfig = union(enum) {
URL: []const u8,
};
-const defaultOutput = OutputConfig{
- .type = .window,
- .width = 800,
- .height = 600,
- .filter = .linear,
- .monitor = "",
- .fullscreen = false,
-};
+const defaultOutput: OutputConfig = .{ .window = .default };
pub const Config = struct {
width: i32,
@@ -60,7 +41,7 @@ pub const Config = struct {
project_root: fs.Dir,
osc: OSCConfig,
- pub fn parse(allocator: *const std.mem.Allocator, filename: []const u8) !Config {
+ 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);
@@ -82,9 +63,9 @@ pub const Config = struct {
.osc = .{ .URL = "osc.udp://:9000" },
};
- try expectEvent(&parser, c.YAML_STREAM_START_EVENT);
- try expectEvent(&parser, c.YAML_DOCUMENT_START_EVENT);
- try expectEvent(&parser, c.YAML_MAPPING_START_EVENT);
+ 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);
while (true) {
var event: c.yaml_event_t = undefined;
@@ -99,22 +80,22 @@ pub const Config = struct {
const key: []const u8 = data.value[0..data.length];
if (std.mem.eql(u8, key, "width")) {
- config.width = try parseInt(&parser, i32);
+ config.width = try yaml.parseInt(&parser, i32);
} else if (std.mem.eql(u8, key, "height")) {
- config.height = try parseInt(&parser, i32);
+ config.height = try yaml.parseInt(&parser, i32);
} else if (std.mem.eql(u8, key, "fragment")) {
- config.fragment = try parseString(&parser, allocator);
+ 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 parseString(&parser, allocator), .{});
+ 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 skipAny(&parser);
+ try yaml.skipAny(&parser);
}
},
else => {
@@ -124,164 +105,95 @@ pub const Config = struct {
}
}
- try expectEvent(&parser, c.YAML_DOCUMENT_END_EVENT);
- try expectEvent(&parser, c.YAML_STREAM_END_EVENT);
+ try yaml.expectEvent(&parser, c.YAML_DOCUMENT_END_EVENT);
+ try yaml.expectEvent(&parser, c.YAML_STREAM_END_EVENT);
return config;
}
};
-fn expectEvent(parser: *c.yaml_parser_t, expectedType: c.yaml_event_type_t) !void {
- 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 != expectedType) {
- debug.print("unexpected event: {}\n", .{event.type});
- return error.InvalidConfiguration;
- }
-}
-
-fn parseStringEvent(event: *c.yaml_event_t, allocator: *const std.mem.Allocator) ![]const u8 {
- if (event.type != c.YAML_SCALAR_EVENT)
- return error.InvalidType;
-
- const data = event.data.scalar;
- const value: []const u8 = data.value[0..data.length];
- return try allocator.dupe(u8, value);
-}
-
-fn parseString(parser: *c.yaml_parser_t, allocator: *const std.mem.Allocator) ![]const u8 {
- var event: c.yaml_event_t = undefined;
- if (c.yaml_parser_parse(parser, &event) != 1)
- return error.YAMLParserError;
- defer c.yaml_event_delete(&event);
-
- return parseStringEvent(&event, allocator);
-}
-
-fn parseInt(parser: *c.yaml_parser_t, comptime T: type) !T {
- 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)
- return error.InvalidType;
-
- const data = event.data.scalar;
- const value: []const u8 = data.value[0..data.length];
- return try std.fmt.parseInt(T, value, 10);
-}
-
-fn parseEnum(parser: *c.yaml_parser_t, comptime T: type) !T {
- 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)
- return error.InvalidType;
-
- const data = event.data.scalar;
- const value: []const u8 = data.value[0..data.length];
-
- inline for (@typeInfo(T).@"enum".fields) |field| {
- if (std.mem.eql(u8, value, field.name))
- return @field(T, field.name);
- }
-
- return error.InvalidValue;
-}
-
-fn parseBool(parser: *c.yaml_parser_t) !bool {
- 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)
- return error.InvalidType;
-
- const data = event.data.scalar;
- const value: []const u8 = data.value[0..data.length];
-
- if (data.style != c.YAML_PLAIN_SCALAR_STYLE)
- return false;
- return std.mem.eql(u8, value, "true") or std.mem.eql(u8, value, "1");
-}
-
-fn parseOutputs(parser: *c.yaml_parser_t, allocator: *const std.mem.Allocator) ![]OutputConfig {
- try expectEvent(parser, c.YAML_SEQUENCE_START_EVENT);
+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) {
- 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")) {
- output.*.type = try parseEnum(parser, OutputConfig.Type);
- } else if (std.mem.eql(u8, key, "width")) {
- output.*.width = try parseInt(parser, i32);
- } else if (std.mem.eql(u8, key, "height")) {
- output.*.height = try parseInt(parser, i32);
- } else if (std.mem.eql(u8, key, "filter")) {
- output.*.filter = try parseEnum(parser, OutputConfig.FilterMode);
- } else if (std.mem.eql(u8, key, "monitor")) {
- output.*.monitor = try parseString(parser, allocator);
- } else if (std.mem.eql(u8, key, "fullscreen")) {
- output.*.fullscreen = try parseBool(parser);
- } else {
- debug.print("unknown key: '{s}'\n", .{key});
- try 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;
- },
- }
+ 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: *const std.mem.Allocator) ![]ParameterConfig {
- try expectEvent(parser, c.YAML_SEQUENCE_START_EVENT);
+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;
@@ -312,14 +224,14 @@ fn parseParameters(parser: *c.yaml_parser_t, allocator: *const std.mem.Allocator
const key: []const u8 = data.value[0..data.length];
if (std.mem.eql(u8, key, "name")) {
- param.*.name = try parseString(parser, allocator);
+ param.*.name = try yaml.parseString(parser, allocator);
have_name = true;
} else if (std.mem.eql(u8, key, "type")) {
- param.*.type = try parseString(parser, allocator);
+ param.*.type = try yaml.parseString(parser, allocator);
have_type = true;
} else {
debug.print("unknown key: '{s}'\n", .{key});
- try skipAny(parser);
+ try yaml.skipAny(parser);
}
},
else => {
@@ -347,14 +259,14 @@ fn parseParameters(parser: *c.yaml_parser_t, allocator: *const std.mem.Allocator
return parameters[0..param_count];
}
-fn parseOSC(parser: *c.yaml_parser_t, allocator: *const std.mem.Allocator) !OSCConfig {
+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 parseStringEvent(&event, allocator);
+ 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});
@@ -375,12 +287,12 @@ fn parseOSC(parser: *c.yaml_parser_t, allocator: *const std.mem.Allocator) !OSCC
const key: []const u8 = data.value[0..data.length];
if (std.mem.eql(u8, key, "protocol")) {
- config.Manual.protocol = try parseEnum(parser, OSCConfig.Protocol);
+ config.Manual.protocol = try yaml.parseEnum(parser, OSCConfig.Protocol);
} else if (std.mem.eql(u8, key, "port")) {
- config.Manual.port = try parseInt(parser, u16);
+ config.Manual.port = try yaml.parseInt(parser, u16);
} else {
debug.print("unknown key: '{s}'\n", .{key});
- try skipAny(parser);
+ try yaml.skipAny(parser);
}
},
else => {
@@ -392,38 +304,3 @@ fn parseOSC(parser: *c.yaml_parser_t, allocator: *const std.mem.Allocator) !OSCC
return config;
}
-
-fn skipAny(parser: *c.yaml_parser_t) !void {
- var event: c.yaml_event_t = undefined;
- var depth: u32 = 0;
- while (true) {
- if (c.yaml_parser_parse(parser, &event) != 1)
- return error.YAMLParserError;
- defer c.yaml_event_delete(&event);
-
- switch (event.type) {
- c.YAML_SCALAR_EVENT => {
- if (depth == 0)
- break;
- },
-
- c.YAML_SEQUENCE_START_EVENT,
- c.YAML_MAPPING_START_EVENT,
- => depth += 1,
-
- c.YAML_SEQUENCE_END_EVENT,
- c.YAML_MAPPING_END_EVENT,
- => {
- depth -= 1;
-
- if (depth == 0)
- break;
- },
-
- else => {
- debug.print("unexpected event: {}\n", .{event.type});
- return error.InvalidConfiguration;
- },
- }
- }
-}
diff --git a/src/main.zig b/src/main.zig
index ae567bd..932fdca 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -28,7 +28,7 @@ pub fn main() !void {
_ = args.next();
const filename = args.next() orelse "config.yaml";
- var config = try cfg.Config.parse(&arena.allocator(), filename);
+ var config = try cfg.Config.parse(arena.allocator(), filename);
_ = c.glfwSetErrorCallback(errorCallback);
@@ -68,11 +68,11 @@ pub fn main() !void {
var outputs = try std.ArrayList(*out.Output).initCapacity(arena.allocator(), config.outputs.len);
defer outputs.deinit();
- for (config.outputs) |output_config| {
+ for (config.outputs) |*output_config| {
try outputs.append(out.Output.create(arena.allocator(), output_config, &constants));
}
defer for (outputs.items) |output| {
- output.destroy(output);
+ output.destroy(arena.allocator());
};
c.glfwMakeContextCurrent(window);
@@ -147,10 +147,10 @@ pub fn main() !void {
fbo.unbind();
for (outputs.items, 0..) |output, i| {
- const close = output.update(output, fbo.texture_id);
+ const close = output.update(fbo.texture_id);
if (close) {
const removed = outputs.swapRemove(i);
- removed.destroy(removed);
+ removed.destroy(arena.allocator());
break;
}
}
diff --git a/src/output.zig b/src/output.zig
index 459bedb..960c8ae 100644
--- a/src/output.zig
+++ b/src/output.zig
@@ -1,31 +1,202 @@
-const c = @import("c.zig");
const std = @import("std");
+const c = @import("c.zig");
+const build_config = @import("build_config");
const cfg = @import("config.zig");
const gl = @import("gl.zig");
+const yaml = @import("yaml.zig");
pub const Output = struct {
- update: *const fn (*Output, c.GLuint) bool,
- destroy: *const fn (*Output) void,
+ update_fn: *const fn (output: *Output, texture_id: c.GLuint) bool,
+ destroy_fn: *const fn (output: *Output, allocator: std.mem.Allocator) void,
- fn init(update: *const fn (*Output, c.GLuint) bool, destroy: *const fn (*Output) void) Output {
- return Output{
- .update = update,
- .destroy = destroy,
+ pub fn create(
+ allocator: std.mem.Allocator,
+ config: *const cfg.OutputConfig,
+ constants: *gl.Constants,
+ ) *Output {
+ return switch (config.*) {
+ .window => |*con| WindowOutput.create(allocator, con, constants),
+ .texture_share_vk => |*con| if (build_config.have_tsv) TSVOutput.create(allocator, con, constants) else unreachable,
};
}
+ pub fn update(self: *Output, texture_id: c.GLuint) bool {
+ return self.update_fn(self, texture_id);
+ }
+
+ pub fn destroy(self: *Output, allocator: std.mem.Allocator) void {
+ return self.destroy_fn(self, allocator);
+ }
+};
+
+pub const TSVOutput = struct {
+ pub const Config = struct {
+ name: [:0]const u8,
+
+ 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,
+ config: *const Config,
+ client: *c.GlClient,
+ image_size: c.GlImageExtent,
+
pub fn create(
allocator: std.mem.Allocator,
- config: cfg.OutputConfig,
+ config: *const Config,
constants: *gl.Constants,
) *Output {
- return switch (config.type) {
- .window => WindowOutput.create(allocator, config, constants),
+ const self = allocator.create(TSVOutput) catch unreachable;
+
+ _ = c.gl_client_initialize_external_gl() or unreachable;
+
+ self.* = .{
+ .output = .{
+ .update_fn = update,
+ .destroy_fn = destroy,
+ },
+ .config = config,
+ .client = c.gl_client_new(c.VK_SERVER_DEFAULT_SOCKET_PATH, 1000) orelse unreachable,
+ .image_size = .{
+ .top_left = .{ 0, 0 },
+ .bottom_right = .{ constants.config.width, constants.config.height },
+ },
};
+
+ _ = c.gl_client_init_image(
+ self.client,
+ config.name,
+ @intCast(constants.config.width),
+ @intCast(constants.config.height),
+ c.R8G8B8A8,
+ true,
+ );
+
+ return &self.output;
+ }
+
+ fn update(output: *Output, texture_id: c.GLuint) bool {
+ const self: *TSVOutput = @fieldParentPtr("output", output);
+
+ var fbo: c.GLint = undefined;
+ c.glGetIntegerv(c.GL_DRAW_FRAMEBUFFER_BINDING, &fbo);
+
+ _ = c.gl_client_send_image(
+ self.client,
+ self.config.name,
+ texture_id,
+ c.GL_TEXTURE_2D,
+ false,
+ @intCast(fbo),
+ &self.image_size,
+ );
+ return false;
+ }
+
+ fn destroy(output: *Output, allocator: std.mem.Allocator) void {
+ const self: *TSVOutput = @fieldParentPtr("output", output);
+
+ allocator.destroy(self);
}
};
pub const WindowOutput = struct {
+ pub const Config = struct {
+ const FilterMode = enum(c.GLuint) {
+ nearest = c.GL_NEAREST,
+ linear = c.GL_LINEAR,
+ };
+
+ width: i32,
+ height: i32,
+ filter: FilterMode,
+
+ monitor: []const u8,
+ fullscreen: bool,
+
+ pub const default: Config = .{
+ .width = 800,
+ .height = 600,
+ .filter = .linear,
+ .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,
window: *c.GLFWwindow,
constants: *gl.Constants,
@@ -34,16 +205,19 @@ pub const WindowOutput = struct {
pub fn create(
allocator: std.mem.Allocator,
- config: cfg.OutputConfig,
+ config: *const Config,
constants: *gl.Constants,
) *Output {
const self = allocator.create(WindowOutput) catch unreachable;
c.glfwDefaultWindowHints();
- self.* = WindowOutput{
+ self.* = .{
.constants = constants,
- .output = Output.init(update, destroy),
+ .output = .{
+ .update_fn = update,
+ .destroy_fn = destroy,
+ },
.window = c.glfwCreateWindow(
config.width,
config.height,
@@ -108,10 +282,11 @@ pub const WindowOutput = struct {
return false;
}
- fn destroy(output: *Output) void {
+ fn destroy(output: *Output, allocator: std.mem.Allocator) void {
const self: *WindowOutput = @fieldParentPtr("output", output);
c.glfwDestroyWindow(self.window);
+ allocator.destroy(self);
}
fn keyCallback(
diff --git a/src/yaml.zig b/src/yaml.zig
new file mode 100644
index 0000000..36e1770
--- /dev/null
+++ b/src/yaml.zig
@@ -0,0 +1,127 @@
+const c = @import("c.zig");
+const std = @import("std");
+const debug = @import("std").debug;
+
+pub fn expectEvent(parser: *c.yaml_parser_t, expectedType: c.yaml_event_type_t) !void {
+ 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 != expectedType) {
+ debug.print("unexpected event: {}\n", .{event.type});
+ return error.InvalidConfiguration;
+ }
+}
+
+pub fn parseStringEvent(event: *c.yaml_event_t, allocator: std.mem.Allocator) ![]const u8 {
+ if (event.type != c.YAML_SCALAR_EVENT)
+ return error.InvalidType;
+
+ const data = event.data.scalar;
+ const value: []const u8 = data.value[0..data.length];
+ return try allocator.dupe(u8, value);
+}
+
+pub fn parseString(parser: *c.yaml_parser_t, allocator: std.mem.Allocator) ![]const u8 {
+ var event: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ return parseStringEvent(&event, allocator);
+}
+
+pub fn parseInt(parser: *c.yaml_parser_t, comptime T: type) !T {
+ 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)
+ return error.InvalidType;
+
+ const data = event.data.scalar;
+ const value: []const u8 = data.value[0..data.length];
+ return try std.fmt.parseInt(T, value, 10);
+}
+
+pub fn parseEnum(parser: *c.yaml_parser_t, comptime T: type) !T {
+ 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)
+ return error.InvalidType;
+
+ const data = event.data.scalar;
+ const value: []const u8 = data.value[0..data.length];
+
+ inline for (@typeInfo(T).@"enum".fields) |field| {
+ if (std.mem.eql(u8, value, field.name))
+ return @field(T, field.name);
+ }
+
+ return error.InvalidValue;
+}
+
+pub fn parseUnion(parser: *c.yaml_parser_t, comptime T: type, allocator: std.mem.Allocator) !T {
+ _ = parser;
+ _ = allocator;
+ // sorry, i lost this code in a git accident and have since moved on 🤡
+ unreachable;
+}
+
+pub fn parseBool(parser: *c.yaml_parser_t) !bool {
+ 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)
+ return error.InvalidType;
+
+ const data = event.data.scalar;
+ const value: []const u8 = data.value[0..data.length];
+
+ if (data.style != c.YAML_PLAIN_SCALAR_STYLE)
+ return false;
+ return std.mem.eql(u8, value, "true") or std.mem.eql(u8, value, "1");
+}
+
+pub fn skipAny(parser: *c.yaml_parser_t) !void {
+ var event: c.yaml_event_t = undefined;
+ var depth: u32 = 0;
+ while (true) {
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ switch (event.type) {
+ c.YAML_SCALAR_EVENT => {
+ if (depth == 0)
+ break;
+ },
+
+ c.YAML_SEQUENCE_START_EVENT,
+ c.YAML_MAPPING_START_EVENT,
+ => depth += 1,
+
+ c.YAML_SEQUENCE_END_EVENT,
+ c.YAML_MAPPING_END_EVENT,
+ => {
+ depth -= 1;
+
+ if (depth == 0)
+ break;
+ },
+
+ else => {
+ debug.print("unexpected event: {}\n", .{event.type});
+ return error.InvalidConfiguration;
+ },
+ }
+ }
+}