--- /dev/null
+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);
+}
--- /dev/null
+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 },
+ });
+}