diff options
| author | Patrick | 2026-10-05 19:01:09 +0200 |
|---|---|---|
| committer | Patrick | 2026-10-05 19:01:09 +0200 |
| commit | bd3f5d3455ed523f58fd292b33db2cece1013cdf (patch) | |
| tree | 5b3b111eda73f59befcb4b0ecd80af5105ad522d | |
| parent | 2e19a1b44b366547563f5c5686455a1227a8fcbd (diff) | |
| download | sg3-main.tar.gz sg3-main.zip | |
| -rw-r--r-- | build.zig | 11 | ||||
| -rw-r--r-- | src/main.zig | 205 | ||||
| -rw-r--r-- | src/shaders/main.glsl | 33 |
3 files changed, 143 insertions, 106 deletions
@@ -60,12 +60,13 @@ pub fn build(b: *std.Build) void { .bytecode = true, }) catch undefined; - const exe = b.addExecutable(.{ + const exe_options: std.Build.ExecutableOptions = .{ .name = "rc2d", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, + .link_libc = true, .imports = &.{ .{ .name = "stbi", .module = tc_stb.mod }, .{ .name = "zigimg", .module = zigimg_dependency.module("zigimg") }, @@ -73,10 +74,10 @@ pub fn build(b: *std.Build) void { .{ .name = cimgui_conf.module_name, .module = dep_cimgui.module(cimgui_conf.module_name) }, }, }), - }); + }; + const exe = b.addExecutable(exe_options); exe.root_module.linkLibrary(dep_sokol.artifact("sokol_clib")); - exe.root_module.link_libc = true; exe.root_module.addCSourceFile(.{.file = b.path("deps/stb/stb_image.c")}); exe.step.dependOn(shader); @@ -86,4 +87,8 @@ pub fn build(b: *std.Build) void { } b.installArtifact(exe); + + const exe_check = b.addExecutable(exe_options); + const check = b.step("check", "Check if it compiles"); + check.dependOn(&exe_check.step); } diff --git a/src/main.zig b/src/main.zig index 238785c..d0f369a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -19,15 +19,16 @@ const shd = @import("shaders/main.glsl.zig"); const state = struct { var alloc: std.mem.Allocator = undefined; var io: std.Io = undefined; + const Width = 800; const Height = 800; - const offscreen = struct { - var pass: sg.Pass = .{}; + const SampleCount = 1; + var show: i32 = 0; + + const raymarch = struct { + var pass_action: sg.PassAction = .{}; var pip: sg.Pipeline = .{}; var bind: sg.Bindings = .{}; - var vs: shd.VsParams = .{ - .position = .{ 0, 0 }, - }; var fs: shd.FsParams = .{ .resolution = .{ Width, Height }, .rayCount = 24, @@ -39,10 +40,18 @@ const state = struct { var pixels_updated: bool = true; var pixels_img: sg.Image = undefined; }; - const display = struct { + const nearest = struct { var pass_action: sg.PassAction = .{}; - var pip: sg.Pipeline = .{}; + var pass: sg.Pass = .{}; + var pip1: sg.Pipeline = .{}; + var pip2: sg.Pipeline = .{}; var bind: sg.Bindings = .{}; + + var render_tex1: sg.View = .{}; + var render_tex2: sg.View = .{}; + var input_tex1: sg.View = .{}; + var input_tex2: sg.View = .{}; + var depth_img: sg.Image = .{}; }; }; @@ -58,56 +67,65 @@ export fn init() void { sappimgui.setup(); ig.igGetIO().*.ConfigFlags |= ig.ImGuiConfigFlags_DockingEnable; - state.offscreen.pass.action.colors[0] = .{ + state.raymarch.pass_action.colors[0] = .{ .load_action = .LOAD, .store_action = .STORE, }; - state.offscreen.pass.action.depth = .{ + state.raymarch.pass_action.depth = .{ .load_action = .LOAD, .store_action = .STORE, }; - state.display.pass_action.colors[0] = .{ + state.nearest.pass_action.colors[0] = .{ .load_action = .CLEAR, }; - const offscreen_width = state.Width; - const offscreen_height = state.Height; - const offscreen_sample_count = 1; - const color_img = sg.makeImage(.{ + state.raymarch.pixels_img = sg.makeImage(.{ + .usage = .{ .dynamic_update = true }, + .width = state.Width, + .height = state.Height, + .sample_count = state.SampleCount, + .pixel_format = .RGBA8, + }); + const nearest_tex1 = sg.makeImage(.{ .usage = .{ .color_attachment = true }, - .width = offscreen_width, - .height = offscreen_height, - .sample_count = offscreen_sample_count, + .width = state.Width, + .height = state.Height, + .sample_count = state.SampleCount, .pixel_format = .RGBA8, }); - state.offscreen.pixels_img = sg.makeImage(.{ - .usage = .{ .dynamic_update = true }, - .width = offscreen_width, - .height = offscreen_height, - .sample_count = offscreen_sample_count, + const nearest_tex2 = sg.makeImage(.{ + .usage = .{ .color_attachment = true }, + .width = state.Width, + .height = state.Height, + .sample_count = state.SampleCount, .pixel_format = .RGBA8, }); - const depth_img = sg.makeImage(.{ + const nearest_depth_img = sg.makeImage(.{ .usage = .{ .depth_stencil_attachment = true }, - .width = offscreen_width, - .height = offscreen_height, - .sample_count = offscreen_sample_count, + .width = state.Width, + .height = state.Height, + .sample_count = state.SampleCount, .pixel_format = .DEPTH, }); - - state.offscreen.pass.attachments.colors[0] = sg.makeView(.{ - .color_attachment = .{ .image = color_img }, + state.nearest.render_tex1 = sg.makeView(.{ + .color_attachment = .{ .image = nearest_tex1 }, }); - state.offscreen.pass.attachments.depth_stencil = sg.makeView(.{ - .depth_stencil_attachment = .{ .image = depth_img }, + state.nearest.render_tex2 = sg.makeView(.{ + .color_attachment = .{ .image = nearest_tex2 }, + }); + state.nearest.input_tex1 = sg.makeView(.{ + .texture = .{ .image = nearest_tex1 }, + }); + state.nearest.input_tex2 = sg.makeView(.{ + .texture = .{ .image = nearest_tex2 }, }); - state.offscreen.bind.views[shd.VIEW_off_tex] = sg.makeView(.{ - .texture = .{ .image = state.offscreen.pixels_img }, + state.raymarch.bind.views[shd.VIEW_off_tex] = sg.makeView(.{ + .texture = .{ .image = state.raymarch.pixels_img }, }); - state.display.bind.views[shd.VIEW_scr_tex] = sg.makeView(.{ - .texture = .{ .image = color_img }, + state.nearest.pass.attachments.depth_stencil = sg.makeView(.{ + .depth_stencil_attachment = .{ .image = nearest_depth_img }, }); const vbuf = sg.makeBuffer(.{ .data = sg.asRange(&[6]f32{ @@ -115,53 +133,63 @@ export fn init() void { -1.0, 3.0, 3.0, -1.0, }) }); - state.offscreen.bind.vertex_buffers[0] = vbuf; - state.display.bind.vertex_buffers[0] = vbuf; + state.raymarch.bind.vertex_buffers[0] = vbuf; + state.nearest.bind.vertex_buffers[0] = vbuf; // shader and pipeline object for the default render pass - state.offscreen.pip = sg.makePipeline(.{ - .shader = sg.makeShader(shd.offscreenShaderDesc(sg.queryBackend())), + state.raymarch.pip = sg.makePipeline(.{ + .shader = sg.makeShader(shd.raymarchShaderDesc(sg.queryBackend())), .layout = init: { var l = sg.VertexLayoutState{}; - l.attrs[shd.ATTR_offscreen_vpos] = .{ .format = .FLOAT2 }; + l.attrs[shd.ATTR_raymarch_vpos] = .{ .format = .FLOAT2 }; break :init l; }, .cull_mode = .BACK, - .sample_count = offscreen_sample_count, .depth = .{ .pixel_format = .DEPTH, .compare = .LESS_EQUAL, .write_enabled = true, }, - .colors = init: { - var c: [sg.max_color_attachments]sg.ColorTargetState = @splat(.{}); - c[0].pixel_format = .RGBA8; - break :init c; - }, }); - state.display.pip = sg.makePipeline(.{ - .shader = sg.makeShader(shd.defaultShaderDesc(sg.queryBackend())), + state.nearest.pip1 = sg.makePipeline(.{ + .shader = sg.makeShader(shd.nearestShaderDesc(sg.queryBackend())), .layout = init: { var l = sg.VertexLayoutState{}; - l.attrs[shd.ATTR_default_vpos] = .{ .format = .FLOAT2 }; + l.attrs[shd.ATTR_nearest_vpos] = .{ .format = .FLOAT2 }; break :init l; }, .cull_mode = .BACK, + .sample_count = state.SampleCount, .depth = .{ + .pixel_format = .DEPTH, .compare = .LESS_EQUAL, .write_enabled = true, }, + .colors = init: { + var c: [sg.max_color_attachments]sg.ColorTargetState = @splat(.{}); + c[0].pixel_format = .RGBA8; + break :init c; + }, + }); + state.nearest.pip2 = sg.makePipeline(.{ + .shader = sg.makeShader(shd.nearestShaderDesc(sg.queryBackend())), + .layout = init: { + var l = sg.VertexLayoutState{}; + l.attrs[shd.ATTR_nearest_vpos] = .{ .format = .FLOAT2 }; + break :init l; + }, + .cull_mode = .BACK, }); // a sampler object for sampling the render target texture - state.offscreen.bind.samplers[shd.SMP_off_smp] = sg.makeSampler(.{ + state.raymarch.bind.samplers[shd.SMP_off_smp] = sg.makeSampler(.{ .min_filter = .LINEAR, .mag_filter = .LINEAR, .wrap_u = .REPEAT, .wrap_v = .REPEAT, }); - state.display.bind.samplers[shd.SMP_scr_smp] = sg.makeSampler(.{ + state.nearest.bind.samplers[shd.SMP_scr_smp] = sg.makeSampler(.{ .min_filter = .LINEAR, .mag_filter = .LINEAR, .wrap_u = .REPEAT, @@ -195,51 +223,72 @@ export fn frame() void { // const dt: f32 = @floatCast(sapp.frameDuration() * 60); // const aspect = sapp.widthf() / sapp.heightf(); - state.offscreen.fs.resolution[0] = sapp.widthf(); - state.offscreen.fs.resolution[1] = sapp.heightf(); + state.raymarch.fs.resolution[0] = sapp.widthf(); + state.raymarch.fs.resolution[1] = sapp.heightf(); if (ig.igBegin("abc", null, 0)) { - // vs - _ = ig.igDragFloat2("position", &state.offscreen.vs.position); - + // general + _ = ig.igInputInt("show", &state.show); // fs - _ = ig.igInputInt("rayCount", &state.offscreen.fs.rayCount); - _ = ig.igInputInt("maxSteps", &state.offscreen.fs.maxSteps); - _ = ig.igDragFloatEx("size", &state.offscreen.fs.size, 1, 0, 1000, "%f", 0); + _ = ig.igInputInt("rayCount", &state.raymarch.fs.rayCount); + _ = ig.igInputInt("maxSteps", &state.raymarch.fs.maxSteps); + _ = ig.igDragFloatEx("size", &state.raymarch.fs.size, 1, 0, 1000, "%f", 0); if (ig.igButton("load png")) { var x: c_int = 0; var y: c_int = 0; var n: c_int = 0; const img = stbi.stbi_load("test.png", &x, &y, &n, 0); - @memcpy(&state.offscreen.pixels, img); + @memcpy(&state.raymarch.pixels, img); stbi.stbi_image_free(img); - state.offscreen.pixels_updated = true; + state.raymarch.pixels_updated = true; } } ig.igEnd(); - if (state.offscreen.pixels_updated) { - state.offscreen.pixels_updated = false; + if (state.raymarch.pixels_updated) { + state.raymarch.pixels_updated = false; var imageData: sg.ImageData = .{}; - imageData.mip_levels[0] = sg.asRange(&state.offscreen.pixels); - sg.updateImage(state.offscreen.pixels_img, imageData); + imageData.mip_levels[0] = sg.asRange(&state.raymarch.pixels); + sg.updateImage(state.raymarch.pixels_img, imageData); } - sg.beginPass(state.offscreen.pass); - sg.applyPipeline(state.offscreen.pip); - sg.applyBindings(state.offscreen.bind); - sg.applyUniforms(shd.UB_vs_params, sg.asRange(&state.offscreen.vs)); - sg.applyUniforms(shd.UB_fs_params, sg.asRange(&state.offscreen.fs)); - sg.draw(0, 3, 1); - sg.endPass(); + if (state.show == 0) { + sg.beginPass(.{ .action = state.raymarch.pass_action, .swapchain = sglue.swapchain() }); + sg.applyPipeline(state.raymarch.pip); + sg.applyBindings(state.raymarch.bind); + sg.applyUniforms(shd.UB_fs_params, sg.asRange(&state.raymarch.fs)); + sg.draw(0, 3, 1); + simgui.render(); + sg.endPass(); + } else if (state.show == 1) { + // render to tex1 + state.nearest.pass.attachments.colors[0] = state.nearest.render_tex1; + state.nearest.bind.views[shd.VIEW_scr_tex] = state.nearest.input_tex2; + sg.beginPass(state.nearest.pass); + sg.applyPipeline(state.nearest.pip1); + sg.applyBindings(state.nearest.bind); + sg.draw(0, 3, 1); + sg.endPass(); - sg.beginPass(.{ .action = state.display.pass_action, .swapchain = sglue.swapchain() }); - sg.applyPipeline(state.display.pip); - sg.applyBindings(state.display.bind); - sg.draw(0, 3, 1); - simgui.render(); - sg.endPass(); + // render from tex1 to tex2 + state.nearest.pass.attachments.colors[0] = state.nearest.render_tex2; + state.nearest.bind.views[shd.VIEW_scr_tex] = state.nearest.input_tex1; + sg.beginPass(state.nearest.pass); + sg.applyPipeline(state.nearest.pip1); + sg.applyBindings(state.nearest.bind); + sg.draw(0, 3, 1); + sg.endPass(); + + // render from tex2 to screen + state.nearest.bind.views[shd.VIEW_scr_tex] = state.nearest.input_tex2; + sg.beginPass(.{.action = state.nearest.pass_action, .swapchain = sglue.swapchain() }); + sg.applyPipeline(state.nearest.pip2); + sg.applyBindings(state.nearest.bind); + sg.draw(0, 3, 1); + simgui.render(); + sg.endPass(); + } sg.commit(); } diff --git a/src/shaders/main.glsl b/src/shaders/main.glsl index 407d2c1..68a1e7e 100644 --- a/src/shaders/main.glsl +++ b/src/shaders/main.glsl @@ -1,19 +1,15 @@ // offscreen rendering shaders -@vs vs_offscreen -layout(binding=0) uniform vs_params { - vec2 position; -}; - +@vs vs_screen in vec2 vpos; out vec2 fpos; void main() { - gl_Position = vec4(vpos + position, 0, 1); + gl_Position = vec4(vpos, 0, 1); fpos = (vpos + 1) * 0.5; } @end -@fs fs_offscreen +@fs fs_raymarch layout(binding=1) uniform texture2D off_tex; layout(binding=1) uniform sampler off_smp; layout(binding=1) uniform fs_params { @@ -31,8 +27,6 @@ bool outOfBounds(vec2 uv) { } #define TAU 6.28318530718 -// #define RAYCOUNT 16 -// #define MAXSTEPS 8 float rand(vec2 seed) { @@ -88,22 +82,10 @@ void main() { } @end -@program offscreen vs_offscreen fs_offscreen - +@program raymarch vs_screen fs_raymarch -// default-pass shaders -@vs vs_default - -in vec2 vpos; -out vec2 fpos; - -void main() { - gl_Position = vec4(vpos, 0, 1); - fpos = (vpos + 1) * 0.5; -} -@end -@fs fs_default +@fs fs_nearest layout(binding=0) uniform texture2D scr_tex; layout(binding=0) uniform sampler scr_smp; @@ -112,8 +94,9 @@ in vec2 fpos; out vec4 frag_color; void main() { - frag_color = texture(sampler2D(scr_tex, scr_smp), fpos); + vec4 t = texture(sampler2D(scr_tex, scr_smp), fpos); + frag_color = vec4(fpos.x, fpos.y, 0, 1) + t; } @end -@program default vs_default fs_default +@program nearest vs_screen fs_nearest |
