diff --git a/.gitignore b/.gitignore index 04d0463..7c0f624 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +ImageSaved* zig-out/ .zig-out/ zig-cache/ diff --git a/Makefile b/Makefile index 1c623b5..b0b2a70 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,13 @@ # All example are built at a time. -EXAMPLE_DIRS := examples/glfw_opengl3 \ - examples/glfw_opengl3_image_load \ - examples/glfw_opengl3_image_save \ - examples/glfw_opengl3_jp \ - examples/sdl2_opengl3 \ - examples/sdl3_opengl3 \ - examples/zig_glfw_opengl3 +EXAMPLE_DIRS := \ + examples/zig_glfw_opengl3 \ + examples/zig_glfw_opengl3_image_load \ + examples/glfw_opengl3 \ + examples/glfw_opengl3_image_load \ + examples/glfw_opengl3_image_save \ + examples/glfw_opengl3_jp \ + examples/sdl2_opengl3 \ + examples/sdl3_opengl3 all: $(foreach exdir,$(EXAMPLE_DIRS), $(call def_make,$(exdir),$@ )) diff --git a/README.md b/README.md index 464f13d..6242a63 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ - [Prerequisites](#prerequisites) - [Build and run](#build-and-run) - [Examples screen shots](#examples-screen-shots) + - [Hiding console window](#hiding-console-window) - [Regenarate ImGui bindings](#regenarate-imgui-bindings) - [Build with Clang, Zig cc](#build-with-clang-zig-cc) - [My tools version](#my-tools-version) @@ -14,7 +15,7 @@ # Dear_Bindings_Build -This project aims to easily build ImGui examples with **C language** and **Zig language** using [Dear_Bindings](https://github.com/dearimgui/dear_bindings). +This project aims to easily build ImGui examples with **C language** and **Zig language** using [Dear_Bindings](https://github.com/dearimgui/dear_bindings) and ImGui. ImGui version **1.90.8 WIP** (2024/05) @@ -69,10 +70,41 @@ ImGui version **1.90.8 WIP** (2024/05) - [glfw_opengl3_image_save](examples/glfw_opengl3_image_save) ![alt](img/glfw_opengl3_image_save.png) + +## Hiding console window + +--- + +- Zig lang. examples +Open `build.zig` in each example folder and **enable** option line as follows, + + ```zig + ... snip ... + exe.subsystem = .Windows; // Hide console window + ... snip ... + ``` + + and execute `make`. + + +- C lang. examples +Open `Makefile` in each example folder and **change** option as follows, + + ```Makefile + ... snip ... + HIDE_CONSOLE_WINDOW = true + ... snip ... + ``` + + and execute `make`. + + ## Regenarate ImGui bindings --- +For instance, + ```sh pwd glfw_opengl3 @@ -95,6 +127,8 @@ glfw_opengl3 make TC=clang # or TC=zigcc ``` +Note: Except Zig lang. examples. + ## My tools version --- diff --git a/examples/compile_flags.txt b/examples/compile_flags.txt new file mode 100644 index 0000000..51a2a6e --- /dev/null +++ b/examples/compile_flags.txt @@ -0,0 +1,35 @@ +-I../libs/sdl/SDL2-2.30.3/i686-w64-mingw32/include/SDL2 +-I../libs/sdl/sdl3/32/SDL3-2024-06-02/SDL3/include + +-Wno-stringop-overflow +-DCIMGUI_USE_GLFW +-DCIMGUI_USE_OPENGL3 +-I../libs/glfw/glfw-3.3.9.bin.WIN32/include +-I../libs/glfw/glfw-3.3.9.bin.WIN64/include +-static +-Wall +-Wno-unused-function +-O2 +-Ilibs/cimgui +-I../libs/imgui +-I. +-I../libs/imgui/backends +-Iutils +-Iutils/fonticon +-I../libs/stb +-DCIMGUI_DEFINE_ENUMS_AND_STRUCTS +-DIMGUI_DISABLE_OBSOLETE_FUNCTIONS=1 +-DImDrawIdx=unsigned int +-DIMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS +-fno-exceptions +-fno-rtti +-std=c++11 + + +# See +# clangdで別ディレクトリのヘッダーを指定したい +# https://qiita.com/sudo00/items/99d9619de38574830f65 +# +# Compiledb +# https://github.com/nickdiego/compiledb +# $ compiledb make diff --git a/examples/glfw_opengl3/Makefile b/examples/glfw_opengl3/Makefile index 9db37b8..a114106 100644 --- a/examples/glfw_opengl3/Makefile +++ b/examples/glfw_opengl3/Makefile @@ -1,4 +1,7 @@ STATIC_GLFW = true + +HIDE_CONSOLE_WINDOW = false + include ../arc.mk include ../glfw_opengl3.mk include ../makefile.common.mk diff --git a/examples/glfw_opengl3/glfw_opengl3.c b/examples/glfw_opengl3/glfw_opengl3.c index 451b496..263bac2 100644 --- a/examples/glfw_opengl3/glfw_opengl3.c +++ b/examples/glfw_opengl3/glfw_opengl3.c @@ -1,6 +1,7 @@ +#include + #include "cimgui.h" #include -#include #include "cimgui_impl_glfw.h" #include "cimgui_impl_opengl3.h" @@ -58,7 +59,7 @@ int main(int argc, char *argv[]) { bool showAnotherWindow = false; ImVec4 clearColor = {.x = 0.25f, .y = 0.55f, .z = 0.90f, .w = 1.00f}; char sBuf[200]; - for (int i = 0; i #include +#include "cimgui.h" #include "cimgui_impl_glfw.h" #include "cimgui_impl_opengl3.h" @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) { bool showDemoWindow = true; bool showAnotherWindow = false; ImVec4 clearColor = {.x = 0.25f, .y = 0.55f, .z = 0.90f, .w = 1.00f}; - char sBuf[200]; + char sBuf[1024]; for (int i = 0; i #include +#include "cimgui.h" #include "cimgui_impl_glfw.h" #include "cimgui_impl_opengl3.h" #include "setupFonts.h" - GLFWwindow *window; int main(int argc, char *argv[]) { @@ -59,11 +58,11 @@ int main(int argc, char *argv[]) { bool showAnotherWindow = false; ImVec4 clearColor = {.x = 0.25f, .y = 0.55f, .z = 0.90f, .w = 1.00f}; char sBuf[200]; - for (int i = 0; i #define SDL_MAIN_HANDLED #include #include +#include "cimgui.h" +#include "cimgui_impl_sdl2.h" +#include "cimgui_impl_opengl3.h" + #include "setupFonts.h" #define nullptr NULL @@ -23,7 +24,7 @@ const int MainWinWidth = 1024; const int MainWinHeight = 800; // Main code -int main(int argc, char *argv[]){ +int main(int argc, char *argv[]) { (void)argc; (void) argv; // Setup SDL if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { @@ -144,7 +145,7 @@ int main(int argc, char *argv[]){ } } if (showAnotherWindow) { - ImGui_Begin("Another Window", &showAnotherWindow,0); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) + ImGui_Begin("Another Window", &showAnotherWindow, 0); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) ImGui_Text("Hello from another window!"); if (ImGui_Button("Close Me")) showAnotherWindow = false; diff --git a/examples/sdl3_opengl3/Makefile b/examples/sdl3_opengl3/Makefile index 67c1ca4..76c62f9 100644 --- a/examples/sdl3_opengl3/Makefile +++ b/examples/sdl3_opengl3/Makefile @@ -10,6 +10,10 @@ LDFLAGS += -luuid -lcomdlg32 -ladvapi32 -lsetupapi -lhid -lversion LDFLAGS += -lws2_32 -ldinput8 -ldxguid -ldxerr8 -lwinmm AFTER_BUILD = @cp -u $(SDL3_DIR)/bin/SDL3.dll . + +# TODO no effect ? +HIDE_CONSOLE_WINDOW = true + include ../makefile.common.mk -gen: $(CIMGUI_ROOT) gencimgui impl_opengl3 impl_sdl3 +gen: $(CIMGUI_DIR) gencimgui impl_opengl3 impl_sdl3 diff --git a/examples/sdl3_opengl3/sdl3_opengl3.c b/examples/sdl3_opengl3/sdl3_opengl3.c index dd63486..ae069e3 100644 --- a/examples/sdl3_opengl3/sdl3_opengl3.c +++ b/examples/sdl3_opengl3/sdl3_opengl3.c @@ -1,18 +1,10 @@ -// Dear ImGui: standalone example application for SDL2 + OpenGL -// (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.) - -// Learn about Dear ImGui: -// - FAQ https://dearimgui.com/faq -// - Getting Started https://dearimgui.com/getting-started -// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). -// - Introduction, links and more at the top of imgui.cpp +#include +#include +#include #include "cimgui.h" #include "cimgui_impl_sdl3.h" #include "cimgui_impl_opengl3.h" -#include -#include -#include #include "setupFonts.h" diff --git a/examples/utils/loadImage.c b/examples/utils/loadImage.c index d56300f..4db8050 100644 --- a/examples/utils/loadImage.c +++ b/examples/utils/loadImage.c @@ -52,9 +52,9 @@ unsigned char* LoadTextureFromFile(const char* imageName, GLuint* out_texture, i /*-------------------- * LoadTitleBarIcon() * ------------------*/ -uint8_t* LoadTitleBarIcon(GLFWwindow* window, const char* iconName) { +unsigned char* LoadTitleBarIcon(GLFWwindow* window, const char* iconName) { int width, height, channels; - uint8_t* pixels = 0; + unsigned char* pixels = 0; if (existsFile(iconName)) { pixels = stbi_load(iconName, &width, &height, &channels, 0); const GLFWimage img = {.width = width, .height = height, .pixels = pixels}; diff --git a/examples/utils/loadImage.h b/examples/utils/loadImage.h index 0984893..15ed654 100644 --- a/examples/utils/loadImage.h +++ b/examples/utils/loadImage.h @@ -1,6 +1,7 @@ #pragma once + unsigned char* LoadTextureFromFile(const char* filename, GLuint* out_texture, int* out_width, int* out_height); #ifdef CIMGUI_USE_GLFW -uint8_t* LoadTitleBarIcon(GLFWwindow* window, const char* iconName); +unsigned char* LoadTitleBarIcon(GLFWwindow* window, const char* iconName); #endif diff --git a/examples/utils/setupFonts.c b/examples/utils/setupFonts.c index f773655..10ab60c 100644 --- a/examples/utils/setupFonts.c +++ b/examples/utils/setupFonts.c @@ -1,52 +1,65 @@ -#include -#include - -#include "cimgui.h" -#include "utils.h" -#include "setupFonts.h" - -const char* IconFontPath = "../utils/fonticon/fa6/fa-solid-900.ttf"; -//const char* JpFontPath = "c:/Windows/Fonts/meiryo.ttc"; -const char* JpFontPath = "c:\\Windows\\Fonts\\meiryo.ttc"; - -/*------------ - * point2px() - *-----------*/ -float point2px(float point) { - //## Convert point to pixel - return (point * 96) / 72; -} - -const ImFontConfig config = {.FontDataOwnedByAtlas = true - , .FontNo = 0 - , .OversampleH = 3 - , .OversampleV = 1 - , .PixelSnapH = false - , .GlyphMaxAdvanceX = FLT_MAX - , .RasterizerMultiply = 1.0 - , .RasterizerDensity = 1.0 - , .MergeMode = true - , .EllipsisChar = -1}; -const ImWchar ranges_icon_fonts[] = {(ImWchar)ICON_MIN_FA, (ImWchar)ICON_MAX_FA, (ImWchar)0}; - -/*-------------- - * setupFonts() - *-------------*/ -void setupFonts(void) { - ImGuiIO* pio = ImGui_GetIO(); - ImFontAtlas_AddFontDefault(pio->Fonts, NULL); - ImFontAtlas_AddFontFromFileTTF(pio->Fonts, IconFontPath, point2px(10), &config - ,ranges_icon_fonts ); - if (false == existsFile(JpFontPath)) { - printf("Error!: Not found JpFontPath: [%s] in %s\n", JpFontPath,__FILE__); - return; - } - printf("Found JpFontPath: [%s]\n",JpFontPath); - - ImFont* font = ImFontAtlas_AddFontFromFileTTF(pio->Fonts, JpFontPath, point2px(14) - , &config - , ImFontAtlas_GetGlyphRangesJapanese(pio->Fonts)); - if (font == NULL) { - printf("Error!: AddFontFromFileTTF(): [%s] \n", JpFontPath); - } -} +#include +#include +#include +#include + +#include "cimgui.h" +#include "utils.h" +#include "setupFonts.h" + +const char* IconFontPath = "../utils/fonticon/fa6/fa-solid-900.ttf"; +const char* JpFontName = "meiryo.ttc"; +char sBufFontPath[2048]; + +/*----------------- + * getFontPath() + *----------------*/ +char* getFontPath(char* sBuf, int bufSize, const char* fontName) { + char* sWinDir = getenv("windir"); + if (sWinDir == NULL) return NULL; + snprintf(sBuf, bufSize, "%s\\Fonts\\%s", sWinDir, fontName); + return sBuf; +} + +/*------------ + * point2px() + *-----------*/ +float point2px(float point) { + //## Convert point to pixel + return (point * 96) / 72; +} + +const ImFontConfig config = {.FontDataOwnedByAtlas = true + , .FontNo = 0 + , .OversampleH = 3 + , .OversampleV = 1 + , .PixelSnapH = false + , .GlyphMaxAdvanceX = FLT_MAX + , .RasterizerMultiply = 1.0 + , .RasterizerDensity = 1.0 + , .MergeMode = true + , .EllipsisChar = -1}; +const ImWchar ranges_icon_fonts[] = {(ImWchar)ICON_MIN_FA, (ImWchar)ICON_MAX_FA, (ImWchar)0}; + +/*-------------- + * setupFonts() + *-------------*/ +void setupFonts(void) { + ImGuiIO* pio = ImGui_GetIO(); + ImFontAtlas_AddFontDefault(pio->Fonts, NULL); + ImFontAtlas_AddFontFromFileTTF(pio->Fonts, IconFontPath, point2px(10), &config + , ranges_icon_fonts); + char* fontPath = getFontPath(sBufFontPath, sizeof(sBufFontPath), JpFontName); + if (false == existsFile(fontPath)) { + printf("Error!: Not found JpFontPath: [%s] in %s\n", fontPath, __FILE__); + return; + } + printf("Found JpFontPath: [%s]\n",fontPath); + + ImFont* font = ImFontAtlas_AddFontFromFileTTF(pio->Fonts, fontPath, point2px(14) + , &config + , ImFontAtlas_GetGlyphRangesJapanese(pio->Fonts)); + if (font == NULL) { + printf("Error!: AddFontFromFileTTF(): [%s] \n", fontPath); + } +} diff --git a/examples/zig_glfw_opengl3/Makefile b/examples/zig_glfw_opengl3/Makefile index 2f2062b..294e715 100644 --- a/examples/zig_glfw_opengl3/Makefile +++ b/examples/zig_glfw_opengl3/Makefile @@ -1,6 +1,8 @@ # Use zig-0.12.0 # by dinau (2024/06) # +TARGET = $(notdir $(CURDIR)) +# OPT += --release=fast #OPT += --release=small # Fail compilation @@ -10,7 +12,7 @@ all: zig build $(OPT) run: all - ./zig-out/bin/glfw_opengl3.exe + ./zig-out/bin/$(TARGET).exe cleanall: rm -fr zig-out diff --git a/examples/zig_glfw_opengl3/build.zig b/examples/zig_glfw_opengl3/build.zig index b10376c..3ffcb68 100644 --- a/examples/zig_glfw_opengl3/build.zig +++ b/examples/zig_glfw_opengl3/build.zig @@ -19,7 +19,7 @@ pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const lib = b.addStaticLibrary(.{ - .name = "glfw_opengl3", + .name = "zig_glfw_opengl3", // In this case the main source file is merely a path, however, in more // complicated build scripts, this could be a generated file. .root_source_file = b.path("src/root.zig"), @@ -33,17 +33,11 @@ pub fn build(b: *std.Build) void { b.installArtifact(lib); const exe = b.addExecutable(.{ - .name = "glfw_opengl3", + .name = "zig_glfw_opengl3", .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }); - - //-------------------------------- - // Define macro for C/C++ sources - //-------------------------------- - exe.root_module.addCMacro("IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS", ""); - exe.root_module.addCMacro("ImDrawIdx", "unsigned int"); //---------------------------------- // Detect 32bit or 64bit Winddws OS //---------------------------------- @@ -65,6 +59,12 @@ pub fn build(b: *std.Build) void { exe.addIncludePath(.{ .path = "../../libs/imgui" }); exe.addIncludePath(.{ .path = "../../libs/stb" }); exe.addIncludePath(.{ .path = "../../libs/imgui/backends" }); + //-------------------------------- + // Define macro for C/C++ sources + //-------------------------------- + exe.root_module.addCMacro("IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS", ""); + exe.root_module.addCMacro("ImDrawIdx", "unsigned int"); + exe.root_module.addCMacro("CIMGUI_USE_GLFW", ""); //--------------- // Sources C/C++ //--------------- @@ -93,6 +93,8 @@ pub fn build(b: *std.Build) void { "../utils/saveImage.c", "../utils/utils.c", }, + .flags = &.{ + }, }); //--------------- // Libs @@ -113,6 +115,7 @@ pub fn build(b: *std.Build) void { // System exe.linkLibC(); exe.linkLibCpp(); + //exe.subsystem = .Windows; // Hide console window // This declares intent for the executable to be installed into the // standard location when the user invokes the "install" step (the default diff --git a/examples/zig_glfw_opengl3/src/main.zig b/examples/zig_glfw_opengl3/src/main.zig index 47125de..2ee3d25 100644 --- a/examples/zig_glfw_opengl3/src/main.zig +++ b/examples/zig_glfw_opengl3/src/main.zig @@ -32,13 +32,6 @@ pub fn main () !void { var bw = std.io.bufferedWriter(stdout_file); const stdout = bw.writer(); - //----------- - // Allocator - //----------- - var arena = std.heap.ArenaAllocator.init (std.heap.page_allocator); - defer arena.deinit (); - const allocator = arena.allocator (); - //------------------- // GLFW initializing //------------------- @@ -112,16 +105,9 @@ pub fn main () !void { var fval: f32 = 0.0; var counter: i32 = 0; // Back ground color - const clearColor = try allocator.alloc (f32, 4); - clearColor[0] = 0.25; - clearColor[1] = 0.55; - clearColor[2] = 0.9; - clearColor[3] = 1.0; - // Text buffer - var sBuf: [200:0]u8 = undefined; - for (sBuf,0..)|_,i| { - sBuf[i] = 0; - } + var clearColor = [_]f32{0.25, 0.55,0.9,1.0}; + // Input text buffer + var sTextInuputBuf = [_:0]u8{0} ** 200; //------------------------ // Select Dear ImGui style @@ -162,15 +148,15 @@ pub fn main () !void { ig.ImGui_Text(ig.IMGUI_VERSION); ig.ImGui_Spacing(); - _ = ig.ImGui_InputTextWithHint("InputText","Input text here", &sBuf, sBuf.len, 0); - ig.ImGui_Text("Input result:"); ig.ImGui_SameLine(); ig.ImGui_Text(&sBuf); + _ = ig.ImGui_InputTextWithHint("InputText","Input text here", &sTextInuputBuf, sTextInuputBuf.len, 0); + ig.ImGui_Text("Input result:"); ig.ImGui_SameLine(); ig.ImGui_Text(&sTextInuputBuf); ig.ImGui_Spacing(); _ = ig.ImGui_Checkbox ("Demo Window", &showDemoWindow); _ = ig.ImGui_Checkbox ("Another Window", &showAnotherWindow); _ = ig.ImGui_SliderFloat ("Float", &fval, 0.0, 1.0); - _ = ig.ImGui_ColorEdit3 ("Clear color", clearColor.ptr, 0); + _ = ig.ImGui_ColorEdit3 ("Clear color", &clearColor, 0); if (ig.ImGui_Button ("Button")) counter += 1; ig.ImGui_SameLine (); diff --git a/examples/zig_glfw_opengl3_image_load/Makefile b/examples/zig_glfw_opengl3_image_load/Makefile new file mode 100644 index 0000000..294e715 --- /dev/null +++ b/examples/zig_glfw_opengl3_image_load/Makefile @@ -0,0 +1,19 @@ +# Use zig-0.12.0 +# by dinau (2024/06) +# +TARGET = $(notdir $(CURDIR)) +# +OPT += --release=fast +#OPT += --release=small +# Fail compilation +#OPT += --release=safe + +all: + zig build $(OPT) + +run: all + ./zig-out/bin/$(TARGET).exe + +cleanall: + rm -fr zig-out + rm -fr zig-cache diff --git a/examples/zig_glfw_opengl3_image_load/build.zig b/examples/zig_glfw_opengl3_image_load/build.zig new file mode 100644 index 0000000..9d7914d --- /dev/null +++ b/examples/zig_glfw_opengl3_image_load/build.zig @@ -0,0 +1,172 @@ +// Use zig-0.12.0 (2024/06) +// +const std = @import("std"); +const builtin = @import("builtin"); + +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. +pub fn build(b: *std.Build) void { + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); + + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); + + const lib = b.addStaticLibrary(.{ + .name = "zig_glfw_opengl3_image_load", + // In this case the main source file is merely a path, however, in more + // complicated build scripts, this could be a generated file. + .root_source_file = b.path("src/root.zig"), + .target = target, + .optimize = optimize, + }); + + // This declares intent for the library to be installed into the standard + // location when the user invokes the "install" step (the default step when + // running `zig build`). + b.installArtifact(lib); + + const exe = b.addExecutable(.{ + .name = "zig_glfw_opengl3_image_load", + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + //---------------------------------- + // Detect 32bit or 64bit Winddws OS + //---------------------------------- + var sBuf: [2048]u8 = undefined; + const Glfw_Base = "../../libs/glfw/glfw-3.3.9.bin.WIN"; + var sArc = "64"; + if(builtin.cpu.arch == std.Target.Cpu.Arch.x86){ + sArc = "32"; + } + const glfw_path = std.fmt.bufPrint(&sBuf, "{s}{s}", .{Glfw_Base,sArc}) catch unreachable; + //--------------- + // Include paths + //--------------- + exe.addIncludePath(.{ .path = b.pathJoin(&.{glfw_path,"include"})}); + exe.addIncludePath(.{ .path = "src" }); + exe.addIncludePath(.{ .path = "../utils" }); + exe.addIncludePath(.{ .path = "../utils/fonticon" }); + exe.addIncludePath(.{ .path = "../libs/cimgui" }); + exe.addIncludePath(.{ .path = "../../libs/imgui" }); + exe.addIncludePath(.{ .path = "../../libs/stb" }); + exe.addIncludePath(.{ .path = "../../libs/imgui/backends" }); + //-------------------------------- + // Define macro for C/C++ sources + //-------------------------------- + exe.root_module.addCMacro("IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS", ""); + exe.root_module.addCMacro("ImDrawIdx", "unsigned int"); + exe.root_module.addCMacro("CIMGUI_USE_GLFW", ""); + //--------------- + // Sources C/C++ + //--------------- + exe.addCSourceFiles(.{ + .files = &.{ + // ImGui main + "../../libs/imgui/imgui.cpp", + "../../libs/imgui/imgui_tables.cpp", + "../../libs/imgui/imgui_demo.cpp", + "../../libs/imgui/imgui_widgets.cpp", + "../../libs/imgui/imgui_draw.cpp", + // CImGui main + "../libs/cimgui/cimgui.cpp", + // ImGui GLFW and OpenGL interface + "../../libs/imgui/backends/imgui_impl_opengl3.cpp", + "../../libs/imgui/backends/imgui_impl_glfw.cpp", + // CImGui GLFW and OpenGL interface + "../libs/cimgui/cimgui_impl_glfw.cpp", + "../libs/cimgui/cimgui_impl_opengl3.cpp", + // CImGui SDL interface + //"../libs/cimgui/cimgui_impl_sdl2.cpp", + //"../libs/cimgui/cimgui_impl_sdl3.cpp", + // utils folder + "../utils/setupFonts.c", + "../utils/loadImage.c", + "../utils/saveImage.c", + "../utils/utils.c", + }, + .flags = &.{ + }, + }); + //--------------- + // Libs + //--------------- + exe.linkSystemLibrary("gdi32"); + exe.linkSystemLibrary("imm32"); + exe.linkSystemLibrary("opengl32"); + exe.linkSystemLibrary("user32"); + exe.linkSystemLibrary("shell32"); + // GLFW + //exe.addLibraryPath(.{.path = b.pathJoin(&.{glfw_path, "lib-mingw-64"})}); + //exe.linkSystemLibrary("glfw3"); // For static link + // Static link + exe.addObjectFile(.{.path = b.pathJoin(&.{glfw_path, "lib-mingw-w64","libglfw3.a"})}); + // Dynamic link + //exe.addObjectFile(.{.path = b.pathJoin(&.{glfw_path, "lib-mingw-w64","libglfw3dll.a"})}); + //exe.linkSystemLibrary("glfw3dll"); // For dynamic link + // System + exe.linkLibC(); + exe.linkLibCpp(); + //exe.subsystem = .Windows; // Hide console window + + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). + b.installArtifact(exe); + + // This *creates* a Run step in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. + const run_cmd = b.addRunArtifact(exe); + + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. + run_cmd.step.dependOn(b.getInstallStep()); + + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + // Creates a step for unit testing. This only builds the test executable + // but does not run it. + const lib_unit_tests = b.addTest(.{ + .root_source_file = b.path("src/root.zig"), + .target = target, + .optimize = optimize, + }); + + const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); + + const exe_unit_tests = b.addTest(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + + // Similar to creating the run step earlier, this exposes a `test` step to + // the `zig build --help` menu, providing a way for the user to request + // running the unit tests. + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_lib_unit_tests.step); + test_step.dependOn(&run_exe_unit_tests.step); +} diff --git a/examples/zig_glfw_opengl3_image_load/build.zig.zon b/examples/zig_glfw_opengl3_image_load/build.zig.zon new file mode 100644 index 0000000..1d4d490 --- /dev/null +++ b/examples/zig_glfw_opengl3_image_load/build.zig.zon @@ -0,0 +1,67 @@ +.{ + .name = "glfw_opengl3", + // This is a [Semantic Version](https://semver.org/). + // In a future version of Zig it will be used for package deduplication. + .version = "0.0.0", + + // This field is optional. + // This is currently advisory only; Zig does not yet do anything + // with this value. + //.minimum_zig_version = "0.11.0", + + // This field is optional. + // Each dependency must either provide a `url` and `hash`, or a `path`. + // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. + // Once all dependencies are fetched, `zig build` no longer requires + // internet connectivity. + .dependencies = .{ + // See `zig fetch --save ` for a command-line interface for adding dependencies. + //.example = .{ + // // When updating this field to a new URL, be sure to delete the corresponding + // // `hash`, otherwise you are communicating that you expect to find the old hash at + // // the new URL. + // .url = "https://example.com/foo.tar.gz", + // + // // This is computed from the file contents of the directory of files that is + // // obtained after fetching `url` and applying the inclusion rules given by + // // `paths`. + // // + // // This field is the source of truth; packages do not come from a `url`; they + // // come from a `hash`. `url` is just one of many possible mirrors for how to + // // obtain a package matching this `hash`. + // // + // // Uses the [multihash](https://multiformats.io/multihash/) format. + // .hash = "...", + // + // // When this is provided, the package is found in a directory relative to the + // // build root. In this case the package's hash is irrelevant and therefore not + // // computed. This field and `url` are mutually exclusive. + // .path = "foo", + + // // When this is set to `true`, a package is declared to be lazily + // // fetched. This makes the dependency only get fetched if it is + // // actually used. + // .lazy = false, + //}, + }, + + // Specifies the set of files and directories that are included in this package. + // Only files and directories listed here are included in the `hash` that + // is computed for this package. + // Paths are relative to the build root. Use the empty string (`""`) to refer to + // the build root itself. + // A directory listed here means that all files within, recursively, are included. + .paths = .{ + // This makes *all* files, recursively, included in this package. It is generally + // better to explicitly list the files and directories instead, to insure that + // fetching from tarballs, file system paths, and version control all result + // in the same contents hash. + "", + // For example... + //"build.zig", + //"build.zig.zon", + //"src", + //"LICENSE", + //"README.md", + }, +} diff --git a/examples/zig_glfw_opengl3_image_load/himeji-400.jpg b/examples/zig_glfw_opengl3_image_load/himeji-400.jpg new file mode 100644 index 0000000..1995217 Binary files /dev/null and b/examples/zig_glfw_opengl3_image_load/himeji-400.jpg differ diff --git a/examples/zig_glfw_opengl3_image_load/icon_qr_my_github_red.png b/examples/zig_glfw_opengl3_image_load/icon_qr_my_github_red.png new file mode 100644 index 0000000..a624ee2 Binary files /dev/null and b/examples/zig_glfw_opengl3_image_load/icon_qr_my_github_red.png differ diff --git a/examples/zig_glfw_opengl3_image_load/imgui.ini b/examples/zig_glfw_opengl3_image_load/imgui.ini new file mode 100644 index 0000000..62159d5 --- /dev/null +++ b/examples/zig_glfw_opengl3_image_load/imgui.ini @@ -0,0 +1,36 @@ +[Window][Debug##Default] +Pos=60,60 +Size=400,400 + +[Window][Dear ImGui Demo] +Pos=441,7 +Size=550,680 + +[Window][Hello, world!] +Pos=16,11 +Size=339,180 + +[Window][Another Window] +Pos=11,312 +Size=198,71 + +[Window][About Dear ImGui] +Pos=66,203 +Size=570,459 + +[Window][Dear ImGui Style Editor] +Pos=60,60 +Size=353,794 + +[Window][ Hello, world!] +Pos=8,7 +Size=339,180 + +[Window][ ImGui: Dear Bindings] +Pos=9,6 +Size=418,335 + +[Window][Image load test] +Pos=8,344 +Size=420,435 + diff --git a/examples/zig_glfw_opengl3_image_load/src/main.zig b/examples/zig_glfw_opengl3_image_load/src/main.zig new file mode 100644 index 0000000..c63fd11 --- /dev/null +++ b/examples/zig_glfw_opengl3_image_load/src/main.zig @@ -0,0 +1,322 @@ +const std = @import ("std"); + +pub const ig = @cImport ({ + @cInclude ("GLFW/glfw3.h"); + @cInclude ("cimgui.h"); + @cInclude ("cimgui_impl_glfw.h"); + @cInclude ("cimgui_impl_opengl3.h"); + @cInclude ("loadImage.h"); + @cInclude ("saveImage.h"); +}); +pub const c = @cImport ({ + @cInclude ("setupFonts.h"); + @cInclude ("IconsFontAwesome6.h"); + @cInclude ("stb_image.h"); + +}); + +const TImgFormat = struct { + kind:[:0]const u8, + ext :[:0]const u8, +}; +const enKind = enum { jpg, png, bmp, tga }; +const ImgFormatTbl = [_]TImgFormat { + TImgFormat {.kind = "JPEG 90%", .ext = ".jpg"} + , TImgFormat {.kind = "PNG ", .ext = ".png"} + , TImgFormat {.kind = "BMP ", .ext = ".bmp"} + , TImgFormat {.kind = "TGA ", .ext = ".tga"} +}; + +var cbItemIndex:usize = @intFromEnum(enKind.jpg); + +// Constants +const SaveImageName = "ImageSaved"; +const IMGUI_HAS_DOCK = false; // true: Can't compile at this time. + +fn glfw_error_callback (err: c_int, description: [*c] const u8) callconv (.C) void +{ + std.debug.print ("GLFW Error {d}: {s}\n", .{ err, description }); +} + +const MainWinWidth :i32 = 1024; +const MainWinHeight:i32 = 800; + +//-------- +// main() +//-------- +pub fn main () !void { + //------------- + // For print() + //------------- + const stdout_file = std.io.getStdOut().writer(); + var bw = std.io.bufferedWriter(stdout_file); + const stdout = bw.writer(); + + //------------------- + // GLFW initializing + //------------------- + _ = ig.glfwSetErrorCallback (glfw_error_callback); + if (ig.glfwInit() == 0) { + try stdout.print("Failed to initialize GLFW: [main.zig]: \n", .{}); + try bw.flush(); // don't forget to flush! + return error.glfwInitFailure; + } + defer ig.glfwTerminate (); + + //------------------------- + // Decide GL+GLSL versions + //------------------------- + const glsl_version = "#version 130"; + ig.glfwWindowHint(ig.GLFW_OPENGL_FORWARD_COMPAT, ig.GLFW_TRUE); + ig.glfwWindowHint(ig.GLFW_OPENGL_PROFILE, ig.GLFW_OPENGL_CORE_PROFILE); + ig.glfwWindowHint(ig.GLFW_CONTEXT_VERSION_MAJOR, 3); + ig.glfwWindowHint(ig.GLFW_CONTEXT_VERSION_MINOR, 3); + // + ig.glfwWindowHint(ig.GLFW_RESIZABLE, ig.GLFW_TRUE); // Resizabe window + ig.glfwWindowHint(ig.GLFW_VISIBLE, ig.GLFW_FALSE); // Needs this if OpenGL is not initialized !. + + //--------------------------------------------- + // Create GLFW window and activate OpenGL libs + //--------------------------------------------- + const window = ig.glfwCreateWindow (MainWinWidth, MainWinHeight, "Dear ImGui example", null, null); + if (window == null) { + ig.glfwTerminate(); + return error.glfwInitFailure; + } + defer ig.glfwDestroyWindow (window); + + ig.glfwMakeContextCurrent(window); + + //------------------------------- + // Visible/Show main window here + //------------------------------- + ig.glfwShowWindow(window); + + ig.glfwSwapInterval(1); // Enable VSync --- Lower CPU load + // + // Load title bar icon + const IconName = "icon_qr_my_github_red.png"; + const pIconData = ig.LoadTitleBarIcon(window, IconName); + defer { + if (pIconData != 0) { + c.stbi_image_free(pIconData); // free memory for icon + } + } + + // Setup Dear ImGui context + if (ig.ImGui_CreateContext (null) == null){ + return error.ImGuiCreateContextFailure; + } + defer ig.ImGui_DestroyContext (null); + + const pio = ig.ImGui_GetIO (); + pio.*.ConfigFlags |= ig.ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + //pio.*.ConfigFlags |= ig.ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + // Setup doncking feature --- can't compile well at this moment. + if (IMGUI_HAS_DOCK) { + pio.*.ConfigFlags |= ig.ImGuiConfigFlags_DockingEnable; // Enable Docking + pio.*.ConfigFlags |= ig.ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows + } + + //------------------------------------- + // ImGui GLFW OpenGL backend interface + //------------------------------------- + _ = ig.cImGui_ImplGlfw_InitForOpenGL(window, true); + defer ig.cImGui_ImplGlfw_Shutdown (); + _ = ig.cImGui_ImplOpenGL3_InitEx(glsl_version); + defer ig.cImGui_ImplOpenGL3_Shutdown (); + + //------------- + // Global vars + //------------- + var showDemoWindow = true; + var showAnotherWindow = false; + var fval: f32 = 0.0; + var counter: i32 = 0; + // Back ground color + var clearColor = [_]f32{0.25, 0.55,0.9,1.0}; + // Input text buffer + var sTextInuputBuf = [_:0]u8{0} ** 200; + + //------------------------ + // Select Dear ImGui style + //------------------------ + ig.ImGui_StyleColorsClassic (null); + //ig.ImGui_StyleColorsDark (null); + //ig.ImGui_StyleColorsLight (null); + + //------------ + // Load image + //------------ + const ImageName = "himeji-400.jpg"; + var textureId : ig.GLuint = undefined; + var textureWidth: c_int = 0; + var textureHeight : c_int = 0; + _ = ig.LoadTextureFromFile(ImageName, &textureId, &textureWidth, &textureHeight); + + c.setupFonts(); // Setup CJK fonts and Icon fonts + + //--------------- + // main loop GUI + //--------------- + while (ig.glfwWindowShouldClose (window) == 0) { + ig.glfwPollEvents (); + // Start the Dear ImGui frame + ig.cImGui_ImplOpenGL3_NewFrame (); + ig.cImGui_ImplGlfw_NewFrame (); + ig.ImGui_NewFrame (); + + //------------------ + // Show demo window + //------------------ + if (showDemoWindow) { + ig.ImGui_ShowDemoWindow (&showDemoWindow); + } + + //------------------ + // Show main window + //------------------ + if ( ig.ImGui_Begin (c.ICON_FA_THUMBS_UP ++ " ImGui: Dear Bindings", null, 0)) { + defer ig.ImGui_End (); + ig.ImGui_Text (c.ICON_FA_COMMENT ++ " GLFW v"); ig.ImGui_SameLine (); + ig.ImGui_Text (ig.glfwGetVersionString()); + ig.ImGui_Text (c.ICON_FA_COMMENT ++ " OpenGL v"); ig.ImGui_SameLine (); + ig.ImGui_Text (ig.glGetString(ig.GL_VERSION)); + ig.ImGui_Text(c.ICON_FA_CIRCLE_INFO ++ " Dear ImGui v"); ig.ImGui_SameLine (); + ig.ImGui_Text(ig.IMGUI_VERSION); + + ig.ImGui_Spacing(); + _ = ig.ImGui_InputTextWithHint("InputText","Input text here", &sTextInuputBuf, sTextInuputBuf.len, 0); + ig.ImGui_Text("Input result:"); ig.ImGui_SameLine(); ig.ImGui_Text(&sTextInuputBuf); + + ig.ImGui_Spacing(); + _ = ig.ImGui_Checkbox ("Demo Window", &showDemoWindow); + _ = ig.ImGui_Checkbox ("Another Window", &showAnotherWindow); + + _ = ig.ImGui_SliderFloat ("Float", &fval, 0.0, 1.0); + _ = ig.ImGui_ColorEdit3 ("Clear color", &clearColor, 0); + + // Save button for capturing window image + ig.ImGui_PushIDInt(0); + ig.ImGui_PushStyleColorImVec4(ig.ImGuiCol_Button, ig.ImVec4 {.x = 0.7, .y = 0.7, .z = 0.0, .w = 1.0}); + ig.ImGui_PushStyleColorImVec4(ig.ImGuiCol_ButtonHovered, ig.ImVec4 {.x = 0.8, .y = 0.8, .z = 0.0, .w = 1.0}); + ig.ImGui_PushStyleColorImVec4(ig.ImGuiCol_ButtonActive, ig.ImVec4 {.x = 0.9, .y = 0.9, .z = 0.0, .w = 1.0}); + ig.ImGui_PushStyleColorImVec4(ig.ImGuiCol_Text, ig.ImVec4 {.x = 0.0, .y = 0.0, .z = 0.0, .w = 1.0}); + + // Image save button + const imageExt = ImgFormatTbl[cbItemIndex].ext; + var svNameBuf:[std.fs.MAX_PATH_BYTES]u8 = undefined; + var svBuf:[std.fs.MAX_PATH_BYTES]u8 = undefined; + const slsName = try std.fmt.bufPrint(&svNameBuf, "{s}_{}{s}", .{SaveImageName, counter, imageExt}); + if (ig.ImGui_Button("Save Image")) { + const wkSize = ig.ImGui_GetMainViewport().*.WorkSize; + const sx:c_int = @intFromFloat(wkSize.x); + const sy:c_int = @intFromFloat(wkSize.y); + _ = c.printf("%s, %d, %d\n", slsName.ptr, sx, sy); + ig.saveImage(slsName.ptr, 0, 0, sx, sy, 3, 90); // # --- Save Image ! + } + ig.ImGui_PopStyleColorEx(4); + ig.ImGui_PopID(); + + // Show tooltip help + const slsBuf = try std.fmt.bufPrint(&svBuf, "Save to {s}", .{slsName}); + setTooltip(slsBuf.ptr); + counter += 1; + + ig.ImGui_SameLine(); + // ComboBox: Select save image format + ig.ImGui_SetNextItemWidth(100); + if (ig.ImGui_BeginCombo("##", ImgFormatTbl[cbItemIndex].kind, 0)) { + for (ImgFormatTbl, 0..)|_, n| { + var is_selected = (cbItemIndex == n); + if (ig.ImGui_SelectableBoolPtr(ImgFormatTbl[n].kind, &is_selected, 0)) { + if (is_selected) { + ig.ImGui_SetItemDefaultFocus(); + } + cbItemIndex = n; + } + } + ig.ImGui_EndCombo(); + } + setTooltip("Select image format"); + + ig.ImGui_Text ("Application average %.3f ms/frame (%.1f FPS)", 1000.0 / pio.*.Framerate, pio.*.Framerate); + // Show icon fonts + ig.ImGui_SeparatorText(c.ICON_FA_WRENCH ++ " Icon font test "); + ig.ImGui_Text(c.ICON_FA_TRASH_CAN ++ " Trash"); + + ig.ImGui_Spacing(); + ig.ImGui_Text(c.ICON_FA_MAGNIFYING_GLASS_PLUS + ++ " " ++ c.ICON_FA_POWER_OFF + ++ " " ++ c.ICON_FA_MICROPHONE + ++ " " ++ c.ICON_FA_MICROCHIP + ++ " " ++ c.ICON_FA_VOLUME_HIGH + ++ " " ++ c.ICON_FA_SCISSORS + ++ " " ++ c.ICON_FA_SCREWDRIVER_WRENCH + ++ " " ++ c.ICON_FA_BLOG); + } + + //--------------------- + // Show another window + //--------------------- + if (showAnotherWindow) { + _ = ig.ImGui_Begin ("Another Window", &showAnotherWindow, 0); + defer ig.ImGui_End (); + ig.ImGui_Text ("Hello from another window!"); + if (ig.ImGui_Button ("Close Me")) showAnotherWindow = false; + } + + // Show image load window + if (ig.ImGui_Begin("Image load test", null, 0)) { + defer ig.ImGui_End(); + // Load image + const size = ig.ImVec2 {.x = @floatFromInt(textureWidth), .y = @floatFromInt(textureHeight)}; + ig.ImGui_SetNextWindowSize(size, ig.ImGuiCond_Always); + + const shortVersion = true; + if (shortVersion) { + ig.ImGui_Image(@ptrFromInt(textureId), size); + } else { // Long version + const uv0 = ig.ImVec2 {.x = 0, .y = 0}; + const uv1 = ig.ImVec2 {.x = 1, .y = 1}; + const tint_col = ig.ImVec4 {.x = 1, .y = 1, .z = 1, .w = 1}; + const border_col = ig.ImVec4 {.x = 0, .y = 0, .z = 0, .w = 0}; + ig.ImGui_ImageEx(@ptrFromInt(textureId), size, uv0, uv1, tint_col, border_col); + } + } + + //----------- + // End procs + //----------- + // Rendering + ig.ImGui_Render (); + ig.glfwMakeContextCurrent(window); + ig.glViewport(0, 0, @intFromFloat(pio.*.DisplaySize.x), @intFromFloat(pio.*.DisplaySize.y)); + ig.glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + ig.glClear(ig.GL_COLOR_BUFFER_BIT); + ig.cImGui_ImplOpenGL3_RenderDrawData(ig.ImGui_GetDrawData()); + // Docking featrue --- N/A + if (IMGUI_HAS_DOCK){ + if (pio.*.ConfigFlags & ig.ImGuiConfigFlags_ViewPortsEnable) { + const backup_current_window = ig.glfwGetCurrentContext(); + ig.ImGui_UpdatePlatformWindows(); + ig.ImGui_RenderPlatformWindowsDefault(); + ig.glfwMakeContextCurrent(backup_current_window); + } + } + ig.glfwSwapBuffers(window); + } // while end +} // main end + + +//-------------- +// setTooltip() +//-------------- +fn setTooltip (str: [*c] const u8) void { + if (ig.ImGui_IsItemHovered(ig.ImGuiHoveredFlags_DelayNormal)) { + if (ig.ImGui_BeginTooltip()) { + ig.ImGui_Text(str); + ig.ImGui_EndTooltip(); + } + } +} diff --git a/examples/zig_glfw_opengl3_image_load/src/root.zig b/examples/zig_glfw_opengl3_image_load/src/root.zig new file mode 100644 index 0000000..ecfeade --- /dev/null +++ b/examples/zig_glfw_opengl3_image_load/src/root.zig @@ -0,0 +1,10 @@ +const std = @import("std"); +const testing = std.testing; + +export fn add(a: i32, b: i32) i32 { + return a + b; +} + +test "basic add functionality" { + try testing.expect(add(3, 7) == 10); +}