//! Build-embedded source behind EffectCode. //! //! Several builtins intentionally share one shader pass. Returning segments //! makes that sharing visible instead of copying or manufacturing a pretend //! per-effect program. const std = @import("std"); const build_config = @import("pardes_config"); const runtime_config = @import("runtime_config.zig"); const panel_math = @embedFile("panel_animation.zig"); const pardes_core = @embedFile("pardes.zig"); const tty_compositor = @embedFile("tty/panel_compositor.zig"); const panel_vertex = @embedFile("effect-source-ui.vert.glsl"); const panel_fragment = @embedFile("effect-source-ui.frag.glsl"); const image_vertex = @embedFile("effect-source-image.vert.glsl"); const image_fragment = @embedFile("effect-source-image.frag.glsl"); const scene_vertex = @embedFile("effect-source-crt.vert.glsl"); const scene_fragment = @embedFile("effect-source-crt.frag.glsl"); const gui_scene_mapping = @embedFile("gui/crt.zig"); const gui_host = @embedFile("gui/gui.zig"); const mac_scene = @embedFile("effect-source-crt.ci.metal"); const mac_postprocessor = @embedFile("macos/Sources/ScenePostprocessor.swift"); const mac_view = @embedFile("macos/Sources/PardesView.swift"); fn sourceSection( comptime source: []const u8, comptime begin_marker: []const u8, comptime end_marker: []const u8, ) []const u8 { // gui.zig is intentionally embedded as the source actually compiled, then // narrowed to its marked host paths. The comptime byte scan is larger than // Zig's small default quota but contributes no runtime work. @setEvalBranchQuota(1_000_000); const begin = std.mem.indexOf(u8, source, begin_marker) orelse @compileError("EffectCode source begin marker is missing"); const body = begin + begin_marker.len; const end = std.mem.indexOfPos(u8, source, body, end_marker) orelse @compileError("EffectCode source end marker is missing"); return source[body..end]; } const gui_panel_host = sourceSection( gui_host, "// EFFECT_CODE_PANEL_HOST_BEGIN\n", "// EFFECT_CODE_PANEL_HOST_END", ); const gui_native_panel = sourceSection( gui_host, "// EFFECT_CODE_NATIVE_PANEL_BEGIN\n", "// EFFECT_CODE_NATIVE_PANEL_END", ); const gui_frame_submission = sourceSection( gui_host, "// EFFECT_CODE_FRAME_SUBMISSION_BEGIN\n", "// EFFECT_CODE_FRAME_SUBMISSION_END", ); const gui_cell_instance = sourceSection( gui_host, "// EFFECT_CODE_CELL_INSTANCE_BEGIN\n", "// EFFECT_CODE_CELL_INSTANCE_END", ); const ascii_diff = sourceSection( pardes_core, "// EFFECT_CODE_ASCII_DIFF_BEGIN\n", "// EFFECT_CODE_ASCII_DIFF_END", ); const ascii_compositor = sourceSection( pardes_core, " // EFFECT_CODE_ASCII_COMPOSITOR_BEGIN\n", " // EFFECT_CODE_ASCII_COMPOSITOR_END", ); const ui_vertex_path = if (build_config.gui_shader_sources_prebuilt) "shaders/prebuilt/ui.vert.glsl" else "shaders/ui.vert.glsl"; const ui_fragment_path = if (build_config.gui_shader_sources_prebuilt) "shaders/prebuilt/ui.frag.glsl" else "shaders/ui.frag.glsl"; const image_vertex_path = if (build_config.gui_shader_sources_prebuilt) "shaders/prebuilt/image.vert.glsl" else "shaders/image.vert.glsl"; const image_fragment_path = if (build_config.gui_shader_sources_prebuilt) "shaders/prebuilt/image.frag.glsl" else "shaders/image.frag.glsl"; const scene_vertex_path = if (build_config.gui_shader_sources_prebuilt) "shaders/prebuilt/crt.vert.glsl" else "shaders/crt.vert.glsl"; const scene_fragment_path = if (build_config.gui_shader_sources_prebuilt) "shaders/prebuilt/crt.frag.glsl" else "shaders/crt.frag.glsl"; pub const Backend = @TypeOf(build_config.platform); pub const backend: Backend = build_config.platform; pub const GuiShaderSourceMode = enum { live, prebuilt_snapshot, pub fn label(mode: GuiShaderSourceMode) []const u8 { return switch (mode) { .live => "live GLSL compiled during this build", .prebuilt_snapshot => "paired GLSL snapshot for committed SPIR-V", }; } }; /// Only the SDL backend consumes GLSL/SPIR-V. Other backends deliberately have /// no shader-source mode rather than being mislabeled "live" or "prebuilt". pub fn guiShaderSourceMode() ?GuiShaderSourceMode { if (backend != .gui) return null; return if (build_config.gui_shader_sources_prebuilt) .prebuilt_snapshot else .live; } pub const Segment = struct { path: []const u8, source: []const u8, }; const tty_panel = [_]Segment{ .{ .path = "src/panel_animation.zig", .source = panel_math }, .{ .path = "src/pardes.zig#ascii-diff", .source = ascii_diff }, .{ .path = "src/pardes.zig#ascii-compositor", .source = ascii_compositor }, .{ .path = "src/tty/panel_compositor.zig", .source = tty_compositor }, }; const gui_panel = [_]Segment{ .{ .path = "src/panel_animation.zig", .source = panel_math }, .{ .path = "src/pardes.zig#ascii-diff", .source = ascii_diff }, .{ .path = "src/pardes.zig#ascii-compositor", .source = ascii_compositor }, .{ .path = "src/gui/gui.zig#panel-host", .source = gui_panel_host }, .{ .path = "src/gui/gui.zig#native-panel", .source = gui_native_panel }, .{ .path = "src/gui/gui.zig#frame-submission", .source = gui_frame_submission }, .{ .path = "src/gui/gui.zig#cell-instance", .source = gui_cell_instance }, .{ .path = ui_vertex_path, .source = panel_vertex }, .{ .path = ui_fragment_path, .source = panel_fragment }, .{ .path = image_vertex_path, .source = image_vertex }, .{ .path = image_fragment_path, .source = image_fragment }, }; const gui_scene = [_]Segment{ .{ .path = "src/gui/crt.zig", .source = gui_scene_mapping }, .{ .path = "src/gui/gui.zig#frame-submission", .source = gui_frame_submission }, .{ .path = scene_vertex_path, .source = scene_vertex }, .{ .path = scene_fragment_path, .source = scene_fragment }, }; const mac_panel = [_]Segment{ .{ .path = "src/panel_animation.zig", .source = panel_math }, .{ .path = "src/pardes.zig#ascii-diff", .source = ascii_diff }, .{ .path = "src/pardes.zig#ascii-compositor", .source = ascii_compositor }, .{ .path = "src/macos/Sources/PardesView.swift", .source = mac_view }, .{ .path = "src/macos/Sources/ScenePostprocessor.swift", .source = mac_postprocessor }, .{ .path = "shaders/crt.ci.metal", .source = mac_scene }, }; const mac_scene_segments = [_]Segment{ .{ .path = "src/macos/Sources/PardesView.swift", .source = mac_view }, .{ .path = "src/macos/Sources/ScenePostprocessor.swift", .source = mac_postprocessor }, .{ .path = "shaders/crt.ci.metal", .source = mac_scene }, }; /// Sources for the backend this executable was built for. Keeping the backend /// compile-time and out of the call signature is important: a TTY binary must /// not carry the macOS host and Metal source merely because another switch arm /// could have returned them. pub fn forSetting(setting: runtime_config.Setting) ?[]const Segment { return switch (setting.action) { .transition => switch (backend) { .tty => &tty_panel, .gui => &gui_panel, .macos => &mac_panel, .web => null, }, .scene => switch (backend) { .gui => &gui_scene, .macos => &mac_scene_segments, .tty, .web => null, }, else => null, }; } test "every current-backend effect exposes embedded implementation code" { for (runtime_config.settings) |setting| switch (setting.action) { .transition => if (backend != .web) { const segments = forSetting(setting) orelse return error.MissingTransitionSource; for (segments) |segment| { try std.testing.expect(segment.path.len > 0); try std.testing.expect(segment.source.len > 0); } } else try std.testing.expect(forSetting(setting) == null), .scene => if (backend == .gui or backend == .macos) { const segments = forSetting(setting) orelse return error.MissingSceneSource; for (segments) |segment| { try std.testing.expect(segment.path.len > 0); try std.testing.expect(segment.source.len > 0); } } else try std.testing.expect(forSetting(setting) == null), else => {}, }; } test "GUI scene EffectCode includes both runtime shader stages" { if (comptime backend == .gui) { try std.testing.expectEqual(@as(usize, 4), gui_scene.len); try std.testing.expectEqualStrings("src/gui/crt.zig", gui_scene[0].path); try std.testing.expectEqualStrings("src/gui/gui.zig#frame-submission", gui_scene[1].path); try std.testing.expectEqualStrings(scene_vertex_path, gui_scene[2].path); try std.testing.expectEqualStrings(scene_fragment_path, gui_scene[3].path); try std.testing.expect(std.mem.indexOf(u8, gui_scene[0].source, "pub fn mapScene") != null); try std.testing.expect(std.mem.indexOf(u8, gui_scene[1].source, "SDL_PushGPUFragmentUniformData") != null); try std.testing.expect(std.mem.indexOf(u8, gui_scene[2].source, "gl_VertexIndex") != null); try std.testing.expect(std.mem.indexOf(u8, gui_scene[3].source, "u_crt.effects") != null); } } test "GUI panel EffectCode includes the actual host paint and submission path" { if (comptime backend == .gui) { try std.testing.expect(std.mem.indexOf(u8, ascii_diff, "pub const PanelCellDiff") != null); try std.testing.expect(std.mem.indexOf(u8, ascii_compositor, "fn composeAsciiTransitions") != null); try std.testing.expect(std.mem.indexOf(u8, gui_panel_host, "fn makePaintPlan") != null); try std.testing.expect(std.mem.indexOf(u8, gui_panel_host, "fn setTransitionFields") != null); try std.testing.expect(std.mem.indexOf(u8, gui_native_panel, "fn prepareNativeImages") != null); try std.testing.expect(std.mem.indexOf(u8, gui_native_panel, "fn drawNativeImagesGpu") != null); try std.testing.expect(std.mem.indexOf(u8, gui_native_panel, "active.visualBox()") != null); try std.testing.expect(std.mem.indexOf(u8, gui_frame_submission, "for (paint_plan.batches") != null); try std.testing.expect(std.mem.indexOf(u8, gui_cell_instance, "fn emitInstance") != null); try std.testing.expect(std.mem.indexOf(u8, gui_cell_instance, "setTransitionFields") != null); try std.testing.expect(std.mem.indexOf(u8, panel_math, "frame_count") != null); try std.testing.expect(std.mem.indexOf(u8, gui_frame_submission, "active.effect == .dissolve") != null); } } test "shader source provenance is GUI-only and follows the build input" { if (comptime backend == .gui) { const expected: GuiShaderSourceMode = if (build_config.gui_shader_sources_prebuilt) .prebuilt_snapshot else .live; try std.testing.expectEqual(expected, guiShaderSourceMode().?); try std.testing.expect(expected.label().len > 0); } else try std.testing.expect(guiShaderSourceMode() == null); } test "mac EffectCode includes the runtime panel and scene wiring" { if (comptime backend == .macos) { try std.testing.expect(std.mem.indexOf(u8, mac_scene, "extern \"C\" float4 pardesPanelClear") != null); try std.testing.expect(std.mem.indexOf(u8, mac_scene, "extern \"C\" float4 pardesPanel") != null); try std.testing.expect(std.mem.indexOf(u8, mac_scene, "extern \"C\" float4 pardesScene") != null); try std.testing.expect(std.mem.indexOf(u8, mac_scene, "already composed in Pardes core") != null); try std.testing.expect(std.mem.indexOf(u8, mac_view, "hideCursor: !tracks.isEmpty") != null); try std.testing.expect(std.mem.indexOf(u8, mac_postprocessor, "panelClearKernel.apply") != null); try std.testing.expect(std.mem.indexOf(u8, mac_postprocessor, "panelKernel.apply") != null); try std.testing.expect(std.mem.indexOf(u8, mac_postprocessor, "sceneKernel.apply") != null); } }