]> gitweb.ps.run Git - sporegirl/commitdiff
Initial commit
authorpatrick-scho <patrick.schoenberger@posteo.de>
Fri, 15 Aug 2025 10:59:15 +0000 (12:59 +0200)
committerpatrick-scho <patrick.schoenberger@posteo.de>
Fri, 15 Aug 2025 10:59:15 +0000 (12:59 +0200)
build.zig [new file with mode: 0644]
build.zig.zon [new file with mode: 0644]
src/main.zig [new file with mode: 0644]
src/shader/quad.glsl [new file with mode: 0644]

diff --git a/build.zig b/build.zig
new file mode 100644 (file)
index 0000000..590d913
--- /dev/null
+++ b/build.zig
@@ -0,0 +1,128 @@
+const std = @import("std");
+const Build = std.Build;
+const OptimizeMode = std.builtin.OptimizeMode;
+const ResolvedTarget = Build.ResolvedTarget;
+const Dependency = Build.Dependency;
+const sokol = @import("sokol");
+const cimgui = @import("cimgui");
+
+pub fn build(b: *Build) !void {
+    const target = b.standardTargetOptions(.{});
+    const optimize = b.standardOptimizeOption(.{});
+
+    const opt_docking = b.option(bool, "docking", "Build with docking support") orelse false;
+
+    // Get the matching Zig module name, C header search path and C library for
+    // vanilla imgui vs the imgui docking branch.
+    const cimgui_conf = cimgui.getConfig(opt_docking);
+
+    // note that the sokol dependency is built with `.with_sokol_imgui = true`
+    const dep_sokol = b.dependency("sokol", .{
+        .target = target,
+        .optimize = optimize,
+        .with_sokol_imgui = true,
+    });
+    const dep_cimgui = b.dependency("cimgui", .{
+        .target = target,
+        .optimize = optimize,
+    });
+
+    // inject the cimgui header search path into the sokol C library compile step
+    dep_sokol.artifact("sokol_clib").addIncludePath(dep_cimgui.path(cimgui_conf.include_dir));
+
+    // shaders
+    dep_sokol.artifact("sokol_clib").addIncludePath(b.path("ext/cimgui"));
+    const dep_shdc = dep_sokol.builder.dependency("shdc", .{});
+    const shdc_step = try sokol.shdc.createSourceFile(b, .{
+        .shdc_dep = dep_shdc,
+        .input = "src/shader/quad.glsl",
+        .output = "src/shader/quad.glsl.zig",
+        .slang = .{ .glsl430 = true },
+    });
+
+    // main module with sokol and cimgui imports
+    const mod_main = b.createModule(.{
+        .root_source_file = b.path("src/main.zig"),
+        .target = target,
+        .optimize = optimize,
+        .imports = &.{
+            .{ .name = "sokol", .module = dep_sokol.module("sokol") },
+            .{ .name = cimgui_conf.module_name, .module = dep_cimgui.module(cimgui_conf.module_name) },
+        },
+    });
+    const mod_options = b.addOptions();
+    mod_options.addOption(bool, "docking", opt_docking);
+    mod_main.addOptions("build_options", mod_options);
+
+    // from here on different handling for native vs wasm builds
+    if (target.result.cpu.arch.isWasm()) {
+        try buildWasm(b, .{
+            .mod_main = mod_main,
+            .dep_sokol = dep_sokol,
+            .dep_cimgui = dep_cimgui,
+            .cimgui_clib_name = cimgui_conf.clib_name,
+        });
+    } else {
+        const exe = try buildNative(b, mod_main);
+        exe.step.dependOn(shdc_step);
+    }
+}
+
+fn buildNative(b: *Build, mod: *Build.Module) !*Build.Step.Compile {
+    const exe = b.addExecutable(.{
+        .name = "demo",
+        .root_module = mod,
+    });
+    b.installArtifact(exe);
+    b.step("run", "Run demo").dependOn(&b.addRunArtifact(exe).step);
+    return exe;
+}
+
+const BuildWasmOptions = struct {
+    mod_main: *Build.Module,
+    dep_sokol: *Dependency,
+    dep_cimgui: *Dependency,
+    cimgui_clib_name: []const u8,
+};
+
+fn buildWasm(b: *Build, opts: BuildWasmOptions) !void {
+    // build the main file into a library, this is because the WASM 'exe'
+    // needs to be linked in a separate build step with the Emscripten linker
+    const demo = b.addLibrary(.{
+        .name = "demo",
+        .root_module = opts.mod_main,
+    });
+
+    // get the Emscripten SDK dependency from the sokol dependency
+    const dep_emsdk = opts.dep_sokol.builder.dependency("emsdk", .{});
+
+    // need to inject the Emscripten system header include path into
+    // the cimgui C library otherwise the C/C++ code won't find
+    // C stdlib headers
+    const emsdk_incl_path = dep_emsdk.path("upstream/emscripten/cache/sysroot/include");
+    opts.dep_cimgui.artifact(opts.cimgui_clib_name).addSystemIncludePath(emsdk_incl_path);
+
+    // all C libraries need to depend on the sokol library, when building for
+    // WASM this makes sure that the Emscripten SDK has been setup before
+    // C compilation is attempted (since the sokol C library depends on the
+    // Emscripten SDK setup step)
+    opts.dep_cimgui.artifact(opts.cimgui_clib_name).step.dependOn(&opts.dep_sokol.artifact("sokol_clib").step);
+
+    // create a build step which invokes the Emscripten linker
+    const link_step = try sokol.emLinkStep(b, .{
+        .lib_main = demo,
+        .target = opts.mod_main.resolved_target.?,
+        .optimize = opts.mod_main.optimize.?,
+        .emsdk = dep_emsdk,
+        .use_webgl2 = true,
+        .use_emmalloc = true,
+        .use_filesystem = false,
+        .shell_file_path = opts.dep_sokol.path("src/sokol/web/shell.html"),
+    });
+    // attach to default target
+    b.getInstallStep().dependOn(&link_step.step);
+    // ...and a special run step to start the web build output via 'emrun'
+    const run = sokol.emRunStep(b, .{ .name = "demo", .emsdk = dep_emsdk });
+    run.step.dependOn(&link_step.step);
+    b.step("run", "Run demo").dependOn(&run.step);
+}
diff --git a/build.zig.zon b/build.zig.zon
new file mode 100644 (file)
index 0000000..bc7ef94
--- /dev/null
@@ -0,0 +1,26 @@
+.{
+    .name = .sporegirl2,
+
+    .version = "0.0.0",
+
+    .fingerprint = 0x1f84a20503bc235e,
+
+    .minimum_zig_version = "0.14.1",
+
+    .dependencies = .{
+        .sokol = .{
+            .url = "git+https://github.com/floooh/sokol-zig.git#zig-0.14.1",
+            .hash = "sokol-0.1.0-pb1HK26VLQC1XOkHDW-5TglgwypAKIHGR2HPOTP6limn",
+        },
+        .cimgui = .{
+            .url = "git+https://github.com/floooh/dcimgui#3b98e0a57fc17cc72fdda6934bd932426778a16e",
+            .hash = "cimgui-0.1.0-44ClkczdkgCE9Z_0ehliUmEJjg-bjQVy1r55RQPw9N10",
+        },
+    },
+
+    .paths = .{
+        "build.zig",
+        "build.zig.zon",
+        "src",
+    },
+}
diff --git a/src/main.zig b/src/main.zig
new file mode 100644 (file)
index 0000000..92e1da5
--- /dev/null
@@ -0,0 +1,119 @@
+const use_docking = @import("build_options").docking;
+const ig = if (use_docking) @import("cimgui_docking") else @import("cimgui");
+const sokol = @import("sokol");
+const slog = sokol.log;
+const sg = sokol.gfx;
+const sapp = sokol.app;
+const sglue = sokol.glue;
+const simgui = sokol.imgui;
+
+const shd = @import("shader/quad.glsl.zig");
+
+const state = struct {
+    var bind: sg.Bindings = .{};
+    var pip: sg.Pipeline = .{};
+    var pass_action: sg.PassAction = .{};
+    var show_first_window: bool = true;
+    var show_second_window: bool = true;
+};
+
+export fn init() void {
+    // initialize sokol-gfx
+    sg.setup(.{
+        .environment = sglue.environment(),
+        .logger = .{ .func = slog.func },
+    });
+
+    // initialize sokol-imgui
+    simgui.setup(.{
+        .logger = .{ .func = slog.func },
+    });
+    if (use_docking) {
+        ig.igGetIO().*.ConfigFlags |= ig.ImGuiConfigFlags_DockingEnable;
+    }
+
+    // a vertex buffer
+    state.bind.vertex_buffers[0] = sg.makeBuffer(.{
+        .data = sg.asRange(&[_]f32{
+            // positions      colors
+            -0.5, 0.5,  0.5, 1.0, 0.0, 0.0, 1.0,
+            0.5,  0.5,  0.5, 0.0, 1.0, 0.0, 1.0,
+            0.5,  -0.5, 0.5, 0.0, 0.0, 1.0, 1.0,
+            -0.5, -0.5, 0.5, 1.0, 1.0, 0.0, 1.0,
+        }),
+    });
+
+    // an index buffer
+    state.bind.index_buffer = sg.makeBuffer(.{
+        .usage = .{ .index_buffer = true },
+        .data = sg.asRange(&[_]u16{ 0, 1, 2, 0, 2, 3 }),
+    });
+
+    // a shader and pipeline state object
+    state.pip = sg.makePipeline(.{
+        .shader = sg.makeShader(shd.quadShaderDesc(sg.queryBackend())),
+        .layout = init: {
+            var l = sg.VertexLayoutState{};
+            l.attrs[shd.ATTR_quad_position].format = .FLOAT3;
+            l.attrs[shd.ATTR_quad_color0].format = .FLOAT4;
+            break :init l;
+        },
+        .index_type = .UINT16,
+    });
+
+    // initial clear color
+    state.pass_action.colors[0] = .{
+        .load_action = .CLEAR,
+        .clear_value = .{ .r = 0.0, .g = 0.5, .b = 1.0, .a = 1.0 },
+    };
+}
+
+export fn frame() void {
+    // call simgui.newFrame() before any ImGui calls
+    simgui.newFrame(.{
+        .width = sapp.width(),
+        .height = sapp.height(),
+        .delta_time = sapp.frameDuration(),
+        .dpi_scale = sapp.dpiScale(),
+    });
+
+    if (ig.igBegin("Hello Dear ImGui!", &state.show_first_window, ig.ImGuiWindowFlags_None)) {
+        _ = ig.igColorEdit3("Background", &state.pass_action.colors[0].clear_value.r, ig.ImGuiColorEditFlags_None);
+        _ = ig.igText("Dear ImGui Version: %s", ig.IMGUI_VERSION);
+        ig.igEnd();
+    }
+
+
+    // call simgui.render() inside a sokol-gfx pass
+    sg.beginPass(.{ .action = state.pass_action, .swapchain = sglue.swapchain() });
+    sg.applyPipeline(state.pip);
+    sg.applyBindings(state.bind);
+    sg.draw(0, 6, 1);
+    simgui.render();
+    sg.endPass();
+    sg.commit();
+}
+
+export fn cleanup() void {
+    simgui.shutdown();
+    sg.shutdown();
+}
+
+export fn event(ev: [*c]const sapp.Event) void {
+    // forward input events to sokol-imgui
+    _ = simgui.handleEvent(ev.*);
+}
+
+pub fn main() void {
+    sapp.run(.{
+        .init_cb = init,
+        .frame_cb = frame,
+        .cleanup_cb = cleanup,
+        .event_cb = event,
+        .window_title = "sokol-zig + Dear Imgui",
+        .width = 800,
+        .height = 600,
+        .icon = .{ .sokol_default = true },
+        .logger = .{ .func = slog.func },
+    });
+}
diff --git a/src/shader/quad.glsl b/src/shader/quad.glsl
new file mode 100644 (file)
index 0000000..b3e7e5c
--- /dev/null
@@ -0,0 +1,25 @@
+/* quad vertex shader */
+@vs vs
+in vec4 position;
+in vec4 color0;
+out vec4 color;
+
+void main() {
+    gl_Position = position;
+    color = color0;
+}
+@end
+
+/* quad fragment shader */
+@fs fs
+in vec4 color;
+out vec4 frag_color;
+
+void main() {
+    frag_color = color;
+}
+@end
+
+/* quad shader program */
+@program quad vs fs
+