NaniNoni
NaniNoni

Reputation: 196

How can I integrate cimgui with GLFW and Vulkan into a zig project?

I'm trying to use GLFW with Vulkan and cimgui. GLFW and Vulkan and being included and linked fine (there were no issues before I included cimgui). I include all of the C into my project like so:

const c = @cImport({
    // C Imgui
    @cDefine("CIMGUI_DEFINE_ENUMS_AND_STRUCTS", {});
    @cInclude("cimgui.h");
    @cInclude("cimgui_impl.h");

    // GLFW and Vulkan
    @cDefine("GLFW_INCLUDE_NONE", {});
    @cDefine("GLFW_INCLUDE_VULKAN", {});
    @cInclude("GLFW/glfw3.h");
    @cInclude("vulkan/vulkan.h");
});

Then, when I create a variable to store window data:

var main_window_data: c.ImGui_ImplVulkanH_Window = null;

I get this error:

src/application.zig:25:24: error: root struct of file '.home.naninoni.src.ray_tracer.zig-cache.o.e4d475f56697871ff2702a77a0125b18.cimport' has no member named 'ImGui_ImplVulkanH_Window'
var main_window_data: c.ImGui_ImplVulkanH_Window = null;

In my build.zig, I'm compiling the C++ sources like so:

const IMGUI_SOURCES = [_][]const u8 {
    "deps/cimgui/cimgui.cpp",

    "deps/cimgui/imgui/imgui_demo.cpp",
    "deps/cimgui/imgui/imgui_draw.cpp",
    "deps/cimgui/imgui/imgui_tables.cpp",
    "deps/cimgui/imgui/imgui.cpp",
    "deps/cimgui/imgui/imgui_widgets.cpp",
};

exe.linkLibC();
exe.linkSystemLibrary("glfw");
exe.linkSystemLibrary("Vulkan");

exe.linkLibCpp();    
exe.addIncludePath("deps/cimgui");
exe.addIncludePath("deps/cimgui/imgui");
exe.addIncludePath("deps/cimgui/imgui/backends");
exe.addIncludePath("deps/cimgui/generator/output");
exe.addCSourceFiles(&IMGUI_SOURCES, &.{});

I tried including imgui_impl_vulkan.h and imgui_impl_glfw.h, but then I got a million errors like these:

error: expected ';' at end of declaration list
    constexpr ImVec4()                                        : x(0.0f), y(0.0f), z(0.0f), w(0.0f) { }

I also tried including imgui_impl_vulkan.h and imgui_impl_glfw.h instead of cimgui_impl.h, but the same thing happened. What am I missing?

Upvotes: 2

Views: 1239

Answers (1)

tiawl
tiawl

Reputation: 31

[SUGGESTION]

I know the post is about cimgui/cimgui. But if you are struggling with it you can consider this option instead:

https://github.com/dearimgui/dear_bindings.

Because I prefer this solution, I did not update this answer for a while. Zig evolved a lot since I wrote this answer. So maybe information in [ORIGINAL ANSWER] and [EDIT] sections are outdated. In this case you really should consider have a look at the link below and/or the imgui/imgui fork packaged for Zig I am maintaining:

https://github.com/tiawl/cimgui.zig


[ORIGINAL ANSWER]

Maybe I am coming too late, but I found a solution so the next guy falling on this topic will not waste time as much as I wasted mine.

First of all, you should generate the backends you need with the cimgui generator:

$ cd deps/cimgui/generator        # The cimgui generator works 
                                  # only in its directory.
$ ./generator.sh -c "glfw vulkan" # Please, pay attention to the 
                                  # doubles quotes.

Later you should delegate this job to your build.zig.

Then add these lines to your @cImport:

const c = @cImport({
    // C Imgui
    @cDefine("CIMGUI_DEFINE_ENUMS_AND_STRUCTS", {});

    // These lines:
    @cDefine("CIMGUI_USE_GLFW", {});
    @cDefine("CIMGUI_USE_VULKAN", {});

    @cInclude("cimgui.h");
    @cInclude("cimgui_impl.h");

    // ! \\ WARNING: // ! \\
    // Maybe you should move these following lines before cImgui
    // @cIncludes and @cDefine, because Imgui depends on for 
    // its backends.
    // GLFW and Vulkan:
    @cDefine("GLFW_INCLUDE_NONE", {});
    @cDefine("GLFW_INCLUDE_VULKAN", {});
    @cInclude("GLFW/glfw3.h");
    @cInclude("vulkan/vulkan.h");
});

Finally you should add these lines in your build.zig:

const IMGUI_SOURCES = [_][]const u8 {
    "deps/cimgui/cimgui.cpp",
    "deps/cimgui/imgui/imgui_demo.cpp",
    "deps/cimgui/imgui/imgui_draw.cpp",
    "deps/cimgui/imgui/imgui_tables.cpp",
    "deps/cimgui/imgui/imgui.cpp",
    "deps/cimgui/imgui/imgui_widgets.cpp",

    // These lines:
    "deps/cimgui/imgui/backends/imgui_impl_glfw.cpp",
    "deps/cimgui/imgui/backends/imgui_impl_vulkan.cpp",
};

[EDIT] - 23/07/2023

Unfortunately, with this changes, your program will go further but you will encounter a new error for each Imgui_Impl* you are using that looks like this:

error: ld.lld: undefined symbol: ImGui_ImplVulkan_Init
    note: referenced by your_file.zig:102 (/path/to/your/zig/file/your_file.zig:102)
    note:               /path/to/your/project/zig-cache/o/289b11a03ec527342c42c8f0bd4fd76e/your_project.o:(your.function.using.ImGui_ImplVulkan_Init)
    note: did you mean to declare ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo*, VkRenderPass_T*) as extern "C"?
    note: defined in: /path/to/your/project/zig-cache/o/34e4e97a5b4f3b2c1930a506bfa38f32/imgui_impl_vulkan.o

You have to make those new modifications to allow your program to compile:

  • Reduce your @cImport as follow:
const c = @cImport({
    // C Imgui
    @cDefine("CIMGUI_DEFINE_ENUMS_AND_STRUCTS", {})
    @cInclude("cimgui.h");

    @cDefine("GLFW_INCLUDE_NONE", {});
    @cDefine("GLFW_INCLUDE_VULKAN", {});
    @cInclude("GLFW/glfw3.h");
    @cInclude("vulkan/vulkan.h");
});
  • Keep the modifications I described in my original answer into your build.zig, but remove this line from your original file:
exe.addIncludePath("deps/cimgui/generator/output");

Into deps/cimgui/cimgui.cpp:

  • Add these includes at the end of the file:
#include "imgui/backends/imgui_impl_glfw.h"
#include "imgui/backends/imgui_impl_vulkan.h"
  • After the includes you just added, for each Imgui_Impl* you are using and you can find into deps/cimgui/generator/output/cimgui_impl.h (that you generate as I described in my original answer), add a new binding function. So for example for CIMGUI_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info,VkRenderPass render_pass), add this function at the end of the file (pay attention to the ig I added before the name of the binding function. You can change it (or change the entire name) by whatever you want but do not use the same function name defined by the backends you want to use):
CIMGUI_API bool igImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info,VkRenderPass render_pass)
{
    return ImGui_ImplVulkan_Init(info,render_pass);
}

Into deps/cimgui/cimgui.h:

  • copy the deps/cimgui/generator/output/cimgui_impl.h content before the very last #endif,
  • remove #ifdef CIMGUI_USE_VULKAN and #ifdef CIMGUI_USE_GLFW and their matching #endif that you recently pasted from deps/cimgui/generator/output/cimgui_impl.h,
  • remove the struct declarations from what you recently added. For example, keep this: typedef struct ImGui_ImplVulkanH_Frame ImGui_ImplVulkanH_FrameSemaphores; or this: struct ImGui_ImplVulkanH_FrameSemaphores; but remove this:
struct ImGui_ImplVulkanH_FrameSemaphores
{
    VkSemaphore ImageAcquiredSemaphore;
    VkSemaphore RenderCompleteSemaphore;
};
  • add those extra macros before the deps/cimgui/generator/output/cimgui_impl.h you freshly pasted:
#define GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vulkan/vulkan.h>

Upvotes: 3

Related Questions