diff options
| author | Gabriel Schneider <[email protected]> | 2026-07-02 20:06:25 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-08-01 15:02:07 -0300 |
| commit | bead9f0b78380d1428f40fdab339c1c8f88fa626 (patch) | |
| tree | 960255de5a2cef661ec5d0ad3220a4b2b1738842 /build.zig | |
| parent | 62ef1882ab7878210f05f06504796849e412c318 (diff) | |
| download | pardes-bead9f0b78380d1428f40fdab339c1c8f88fa626.tar.gz pardes-bead9f0b78380d1428f40fdab339c1c8f88fa626.zip | |
sdl ui backend
Diffstat (limited to 'build.zig')
| -rw-r--r-- | build.zig | 81 |
1 files changed, 81 insertions, 0 deletions
@@ -16,6 +16,12 @@ pub fn build(b: *std.Build) void { const static_link = b.option(bool, "static", "link all build executables and test binaries statically") orelse false; const exe_linkage: ?std.builtin.LinkMode = if (static_link) .static else null; const strip = b.option(bool, "strip", "strip debug info from the compiled pardes binary") orelse false; + // -Dsdl: build the SDL3 GPU UI frontend (a windowed cell-grid renderer) + // instead of the default libvaxis terminal backend. The sdl/stb deps are + // lazy, so a plain `zig build` never fetches or compiles them; they're only + // pulled in when this flag is set. Use `zig build test-sdl -Dsdl` for the + // rendered-image SDL e2e suite. + const sdl = b.option(bool, "sdl", "build the SDL3 GPU UI frontend instead of the terminal backend") orelse false; const exe = b.addExecutable(.{ .name = "pardes", @@ -93,6 +99,50 @@ pub fn build(b: *std.Build) void { vaxis_mod.addImport("uucode", uucode_mod); exe.root_module.addImport("vaxis", vaxis_mod); + // The UI backend module (`-Dui`). main.zig + image.zig import `"ui"` instead of + // `"vaxis"` directly; the chosen backend file re-exports the shared UI types + // (Key/Mouse/Window/Cell/…) and provides the renderer/loop (`Vaxis`/`Tty`/ + // `Loop`/`init`). vaxis = transparent passthrough; sdl = SDL3 GPU frontend. + const ui_root = if (sdl) b.path("ui_sdl.zig") else b.path("ui_vaxis.zig"); + const ui_mod = b.createModule(.{ + .target = target, + .optimize = optimize, + .root_source_file = ui_root, + }); + ui_mod.addImport("vaxis", vaxis_mod); + exe.root_module.addImport("ui", ui_mod); + + // SDL3 GPU backend wiring (`-Dsdl`). The sdl package builds SDL3 from source + // as a static lib + emits the SDL3/ headers; we @cImport those headers in + // ui_sdl.zig, link the lib, and pull in stb_truetype (for the glyph atlas) and + // the embedded DejaVuSansMono font. All gated on the flag so a plain `zig build` + // (vaxis) never fetches or compiles SDL. + if (sdl) { + const sdl_dep = b.lazyDependency("sdl", .{ + .target = target, + .optimize = optimize, + }) orelse return; // not fetched (offline?) — skip SDL wiring + const sdl_lib = sdl_dep.artifact("SDL3"); + ui_mod.linkLibrary(sdl_lib); + ui_mod.addIncludePath(sdl_dep.path("include")); + ui_mod.link_libc = true; + + // stb_truetype: the header (declarations, via include path) + the impl TU + // + a small C shim (font.c) so ui_sdl.zig doesn't feed the whole + // single-header lib to translate-c. + ui_mod.addIncludePath(b.path("vendor/stb")); + ui_mod.addCSourceFile(.{ .file = b.path("vendor/stb/stb_truetype_impl.c") }); + ui_mod.addCSourceFile(.{ .file = b.path("vendor/stb/font.c") }); + + // GLSL -> SPIR-V at build time, embedded into ui_sdl.zig via @embedFile. + ui_mod.addAnonymousImport("ui.vert.spv", .{ + .root_source_file = compileGlsl(b, "shaders/ui.vert.glsl", "vertex", "ui.vert.spv"), + }); + ui_mod.addAnonymousImport("ui.frag.spv", .{ + .root_source_file = compileGlsl(b, "shaders/ui.frag.glsl", "fragment", "ui.frag.spv"), + }); + } + // zstbi: C (stb_image)-backed image decoder for the image-viewer panes. We use // it instead of zigimg because zigimg's pure-Zig decoder crashes the Zig 0.16 // compiler here; stb_image is plain C (extern fns), so it compiles fine, decodes @@ -201,6 +251,28 @@ pub fn build(b: *std.Build) void { const test_step = b.step("test", "run deterministic tests"); test_step.dependOn(&run_tests.step); + // `test-sdl`: e2e tests for the SDL3 GPU backend. The SDL pardes exe runs in + // test mode (PARDES_TEST=1): stdin drives app events through a pty, while the + // real GPU renderer writes the latest framebuffer capture to a temp PPM file. + // Requires `-Dsdl` so the SDL exe is the one under test. + const sdl_tests = b.addExecutable(.{ + .name = "pardes-e2e-sdl", + .linkage = exe_linkage, + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("tests_sdl.zig"), + .link_libc = true, + }), + }); + const run_sdl_tests = b.addRunArtifact(sdl_tests); + run_sdl_tests.addArtifactArg(exe); + const sdl_test_opts = b.addOptions(); + sdl_test_opts.addOption(bool, "trace", trace); + sdl_tests.root_module.addOptions("config", sdl_test_opts); + const test_sdl_step = b.step("test-sdl", "run SDL3 GPU e2e tests (requires -Dsdl)"); + test_sdl_step.dependOn(&run_sdl_tests.step); + // Unit tests for the pure modal-editing math (modal.zig has no vaxis/ghostty // deps, so `zig test` on it is fast and needs no wired-in modules). const unit_tests = b.addTest(.{ @@ -254,3 +326,12 @@ pub fn build(b: *std.Build) void { tutor_step.dependOn(&run_tutor.step); test_step.dependOn(&run_tutor.step); } + +// glslc <src> -fshader-stage=<stage> -o <out> -> .spv, returned as a LazyPath to +// @embedFile. Only used by the SDL3 GPU UI backend (`-Dui=sdl`). +fn compileGlsl(b: *std.Build, src: []const u8, stage: []const u8, out: []const u8) std.Build.LazyPath { + const cmd = b.addSystemCommand(&.{ "glslc", b.fmt("-fshader-stage={s}", .{stage}) }); + cmd.addFileArg(b.path(src)); + cmd.addArg("-o"); + return cmd.addOutputFileArg(out); +} |
