1
Note that Dear ImGui can run with different backends - OpenGL, Vulkan, DirectX11, DirectX12, etc.
I use OpenGL and GLFW3, which means the libraries I link to in addition to Dear ImGui can differ from what you'd use.
I have also skipped the parts related to my OpenGL setup (what I link, how I init OpenGL and GLFW) in the steps below.
So, basically what I do:
1) Clone cimgui as described in https://github.com/cimgui/cimgui/blob/docking_inter/README.md :
git clone --recursive https://github.com/cimgui/cimgui.git
Note that this command also clones Dear ImGui to cimgui/imgui , so you don't have to do anything to get Dear ImGui.
2) Optional step: since I load a custom TTF font, I need to initialize a ImFontConfig structure, and cimgui by default doesn't provide access to its constructor, which is helpful, since non all initial values of its fields are zeros.
Because I want to call this constructor, I have to regenerate cimgui with `constructors` flag. To do this, I go to cimgui/generator directory and run `./generator.sh -t "internal noimstrv constructors"` command.
If you don't care about calling structure constructors, you can skip this.
3) In build.zig, add the following lines after `const exe = b.addExecutable(. . .);` and before `b.installArtifact(exe);` -
exe.linkLibC(); // I need C standard library for GLFW anyway, but it may also be needed for cimgui, I'm not 100% sure.
// --== C++ stuff ==--
// Both Dear Imgui and cimgui are C++ libraries, after all. Even if cimgui is a thin wrapper over
// Dear Imgui consisting of `extern "C"` functions, we still need a C++ compiler to build it.
const cimgui_path = "../../cimgui/";
const cimgui_gen_out_path = cimgui_path ++ "generator/output/"; // cimgui_impl.h lives here
const imgui_path = cimgui_path ++ "imgui/";
const imgui_backend_path = imgui_path ++ "backends/";
exe.addIncludePath(std.Build.LazyPath { .cwd_relative = imgui_path });
exe.addIncludePath(std.Build.LazyPath { .cwd_relative = imgui_backend_path });
exe.addIncludePath(std.Build.LazyPath { .cwd_relative = cimgui_gen_out_path });
const cpp_flags: []const []const u8 = &[_][]const u8
{
//"-O2",
"-g",
"-ffunction-sections",
"-fdata-sections",
"-DIMGUI_DISABLE_OBSOLETE_FUNCTIONS=1",
"-DIMGUI_IMPL_API=extern \"C\" ",
};
exe.linkLibCpp(); // Dear Imgui uses C++ standard library
// --- Dear ImGui proper ---
exe.addCSourceFile(std.Build.Module.CSourceFile { .file = .{ .cwd_relative = imgui_path ++ "imgui.cpp" }, .flags = cpp_flags });
exe.addCSourceFile(std.Build.Module.CSourceFile { .file = .{ .cwd_relative = imgui_path ++ "imgui_demo.cpp" }, .flags = cpp_flags });
exe.addCSourceFile(std.Build.Module.CSourceFile { .file = .{ .cwd_relative = imgui_path ++ "imgui_draw.cpp" }, .flags = cpp_flags });
exe.addCSourceFile(std.Build.Module.CSourceFile { .file = .{ .cwd_relative = imgui_path ++ "imgui_tables.cpp" }, .flags = cpp_flags });
exe.addCSourceFile(std.Build.Module.CSourceFile { .file = .{ .cwd_relative = imgui_path ++ "imgui_widgets.cpp" }, .flags = cpp_flags });
exe.addCSourceFile(std.Build.Module.CSourceFile { .file = .{ .cwd_relative = imgui_backend_path ++ "imgui_impl_glfw.cpp" }, .flags = cpp_flags });
exe.addCSourceFile(std.Build.Module.CSourceFile { .file = .{ .cwd_relative = imgui_backend_path ++ "imgui_impl_opengl3.cpp" }, .flags = cpp_flags });
// --- CImGui wrapper ---
exe.addIncludePath(std.Build.LazyPath { .cwd_relative = cimgui_path });
exe.addCSourceFile(std.Build.Module.CSourceFile { .file = .{ .cwd_relative = cimgui_path ++ "cimgui.cpp" }, .flags = cpp_flags });
4) In main.zig:
const c = @cImport(
{
@cDefine("CIMGUI_DEFINE_ENUMS_AND_STRUCTS", {});
@cDefine("CIMGUI_USE_OPENGL3", {}); // This is specific to my backend, you may have to define a different macro/const
@cDefine("CIMGUI_USE_GLFW", {}); // This is specific to my backend, you may have to define a different macro/const
@cInclude("cimgui.h");
@cInclude("cimgui_impl.h");
@cInclude("glad/glad.h"); // This is specific to my backend - this is how I use OpenGL, you probably don't need this
@cInclude("GLFW/glfw3.h"); // This is specific to my backend, you probably don't need this
});
Note that in your .zig-cache/o folder, you're going to find a file called cimport.zig in one of the subfolders, this file contains Zig definitions translated from C headers included with `@cImport`/`@cInclude`.
Very handy for reference.
Then I create my GLFW window, load OpenGL, and then I can init ImGui -
_ = c.igCreateContext(null);
defer c.igDestroyContext(null);
// set docking
ioptr = c.igGetIO(); // [*c]ImGuiIO
if (ioptr == null)
{
std.log.err("igGetIO() returned null\n", .{});
return;
}
// Without .* i'm getting this error:
// error: type 'cimport.struct_ImGuiIO' does not support field access
ioptr.*.ConfigFlags |= c.ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//ioptr.ConfigFlags |= c.ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
if (c.IMGUI_HAS_DOCK != 0) // #ifdef IMGUI_HAS_DOCK
{
ioptr.*.ConfigFlags |= c.ImGuiConfigFlags_DockingEnable; // Enable Docking
//ioptr.*.ConfigFlags |= c.ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
}
// APPLE -> GL 3.2 Core + GLSL 150, others -> GL 3.2 + GLSL 130
const ig_glsl_version = comptime if (builtin.os.tag == .macos) "#version 150" else "#version 130";
_ = c.ImGui_ImplGlfw_InitForOpenGL(window, true);
defer c.ImGui_ImplGlfw_Shutdown();
//
_ = c.ImGui_ImplOpenGL3_Init(ig_glsl_version);
defer c.ImGui_ImplOpenGL3_Shutdown();
And so on.
This is a part of a "sandbox" project I've been playing with, so overall it's messy at the moment, but I could clean it up and publish as a skeleton project, if there's interest.
For immediate assistance, please email our customer support: [email protected]