From a053e62c779b1ba303e21330b266a1b32d26b27a Mon Sep 17 00:00:00 2001 From: David Allemang Date: Sun, 30 Jun 2024 23:19:51 -0400 Subject: [PATCH] initial commit - it's working --- .gitignore | 3 ++ build.zig | 88 +++++++++++++++++++++++++++++++++++++++++++++ build.zig.zon | 19 ++++++++++ demo/build.zig | 28 +++++++++++++++ demo/build.zig.zon | 12 +++++++ demo/src/main.zig | 30 ++++++++++++++++ src/root.zig | 17 +++++++++ zig-cimgui-tasks.md | 15 ++++++++ 8 files changed, 212 insertions(+) create mode 100644 .gitignore create mode 100644 build.zig create mode 100644 build.zig.zon create mode 100644 demo/build.zig create mode 100644 demo/build.zig.zon create mode 100644 demo/src/main.zig create mode 100644 src/root.zig create mode 100644 zig-cimgui-tasks.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6265a1f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +.zig-cache/ +zig-out/ diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..49f807b --- /dev/null +++ b/build.zig @@ -0,0 +1,88 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const imgui_dep = b.dependency("imgui", .{}); + const cimgui_dep = b.dependency("cimgui", .{}); + + const luajit = try b.findProgram(&.{"luajit"}, &.{}); + + const gen = b.addSystemCommand(&.{luajit}); + gen.setCwd(cimgui_dep.path("generator/")); + gen.addFileArg(cimgui_dep.path("generator/generator.lua")); + gen.addArgs(&.{ + "zig cc", + "comments internal noimstrv", + "glfw", + "vulkan", + }); + _ = gen.captureStdOut(); // to quiet output + + { + const relpath = try std.fs.path.relative( + b.allocator, + cimgui_dep.path("generator").getPath(b), + imgui_dep.path("").getPath(b), + ); + defer b.allocator.free(relpath); + gen.setEnvironmentVariable( + "IMGUI_PATH", + relpath, + ); + } + + const copy = b.addWriteFiles(); + copy.step.dependOn(&gen.step); + _ = copy.addCopyDirectory(imgui_dep.path(""), "imgui", .{ + .include_extensions = &.{ ".h", ".cpp" }, + }); + _ = copy.addCopyFile(cimgui_dep.path("cimgui.h"), "cimgui.h"); + _ = copy.addCopyFile(cimgui_dep.path("cimgui.cpp"), "cimgui.cpp"); + _ = copy.addCopyFile(cimgui_dep.path("generator/output/cimgui_impl.h"), "cimgui_impl.h"); + + const cimgui = b.addSharedLibrary(.{ + .name = "cimgui", + .target = target, + .optimize = optimize, + }); + cimgui.step.dependOn(©.step); + cimgui.linkLibC(); + cimgui.linkLibCpp(); + cimgui.addIncludePath(copy.getDirectory()); + cimgui.addIncludePath(copy.getDirectory().path(b, "imgui")); + cimgui.addCSourceFiles(.{ + .root = copy.getDirectory(), + .files = &.{ + "cimgui.cpp", + "imgui/imgui.cpp", + "imgui/imgui_tables.cpp", + "imgui/imgui_widgets.cpp", + "imgui/imgui_demo.cpp", + "imgui/imgui_draw.cpp", + "imgui/backends/imgui_impl_glfw.cpp", + "imgui/backends/imgui_impl_vulkan.cpp", + }, + .flags = &.{ + "-DIMGUI_IMPL_VULKAN_NO_PROTOTYPES", + }, + }); + cimgui.installHeader(copy.getDirectory().path(b, "cimgui.h"), "cimgui.h"); + cimgui.installHeader(copy.getDirectory().path(b, "cimgui_impl.h"), "cimgui_impl.h"); + + cimgui.linkSystemLibrary2("glfw3", .{ + .needed = true, + .preferred_link_mode = .static, + .use_pkg_config = .force, + }); + + b.installArtifact(cimgui); + + const zimgui_mod = b.addModule("zimgui", .{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("src/root.zig"), + }); + zimgui_mod.linkLibrary(cimgui); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..746b1fc --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,19 @@ +.{ + .name = "zimgui", + .version = "0.0.0", + .dependencies = .{ + .cimgui = .{ + .url = "https://github.com/cimgui/cimgui/archive/refs/tags/1.90.8dock.tar.gz", + .hash = "12207ee69164f88f4b41ee5d44edf3835ec4dab0c0cd885799da67d56668f4a3d46b", + }, + .imgui = .{ + .url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.90.8-docking.tar.gz", + .hash = "122065151b97161e25abb71c9df2fd9fba42aaca8c33d689a480b883d82411c8fabe", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/demo/build.zig b/demo/build.zig new file mode 100644 index 0000000..f757112 --- /dev/null +++ b/demo/build.zig @@ -0,0 +1,28 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + // const cimgui = b.dependency("zimgui", .{}).artifact("cimgui"); + const zimgui = b.dependency("zimgui", .{}); + + const exe = b.addExecutable(.{ + .name = "demo", + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + exe.root_module.addImport("zimgui", zimgui.module("zimgui")); + exe.linkSystemLibrary2("glfw3", .{}); + b.installArtifact(exe); + + const run_cmd = b.addRunArtifact(exe); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); +} diff --git a/demo/build.zig.zon b/demo/build.zig.zon new file mode 100644 index 0000000..415d561 --- /dev/null +++ b/demo/build.zig.zon @@ -0,0 +1,12 @@ +.{ + .name = "demo", + .version = "0.0.0", + .dependencies = .{ + .zimgui = .{ .path=".." }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/demo/src/main.zig b/demo/src/main.zig new file mode 100644 index 0000000..a57d319 --- /dev/null +++ b/demo/src/main.zig @@ -0,0 +1,30 @@ +const std = @import("std"); + +const im = @import("zimgui"); + +const c = @cImport({ + @cDefine("GLFW_INCLUDE_NONE", {}); + @cInclude("GLFW/glfw3.h"); +}); + +pub fn main() !void { + im.init(); + defer im.deinit(); + + _ = c.glfwInit(); + defer c.glfwTerminate(); + + const w = c.glfwCreateWindow(1280, 720, "hello", null, null); + defer c.glfwDestroyWindow(w); + + while (c.glfwWindowShouldClose(w) != c.GLFW_TRUE) { + c.glfwPollEvents(); + } +} + +test "simple test" { + var list = std.ArrayList(i32).init(std.testing.allocator); + defer list.deinit(); // try commenting this out and see if zig detects the memory leak! + try list.append(42); + try std.testing.expectEqual(@as(i32, 42), list.pop()); +} diff --git a/src/root.zig b/src/root.zig new file mode 100644 index 0000000..7d6e9e0 --- /dev/null +++ b/src/root.zig @@ -0,0 +1,17 @@ +const std = @import("std"); + +const c = @cImport({ + @cDefine("CIMGUI_DEFINE_ENUMS_AND_STRUCTS", {}); + @cInclude("cimgui.h"); + @cInclude("cimgui_impl.h"); +}); + +pub fn init() void { + _ = c.igCreateContext(null); + std.debug.print("Context Created!\n", .{}); +} + +pub fn deinit() void { + _ = c.igDestroyContext(null); + std.debug.print("Context Destroyed!\n", .{}); +} diff --git a/zig-cimgui-tasks.md b/zig-cimgui-tasks.md new file mode 100644 index 0000000..c8e7e91 --- /dev/null +++ b/zig-cimgui-tasks.md @@ -0,0 +1,15 @@ +- Export `IMGUI_PATH` environment variable to downloaded package. +- cd `generator` directory +- `luajit generator.lua 'zig cc' 'comments internal noimstrv' glfw vulkan` +- compile cimgui/cimgui.cpp, imgui/*.cpp, imgui/backends/*.cpp all together +- install cimgui/cimgui.h, imgui/*.h, cimgui/generator/output/cimgui_impl.h + +Zig needs to access cimgui.h and cimgui_impl.h + +Set a custom loader. Instructions in imgui_impl_vulkan.h + +- cdefine `IMGUI_IMPL_VULKAN_NO_PROTOTYPES` +- call `ImGui_ImplVulkan_LoadFunctions` before `ImGui_ImplVulkan_Init` + +not quite sure yet what the role of `ImGui_ImplVulkanH_Window.UseDynamicRendering` is +