diff --git a/CMakeLists.txt b/CMakeLists.txt index d338db87..025d21b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,11 +46,13 @@ include(hello_imgui_add_app) # - HELLOIMGUI_USE_SDL_OPENGL3 will be used for Android, iOS and emscripten #------------------------------------------------------------------------------ # Use Glfw3 + OpenGl3 -option(HELLOIMGUI_USE_GLFW_OPENGL3 "Build HelloImGui for GLFW+OpenGL3" OFF) +option(HELLOIMGUI_USE_GLFW_OPENGL3 "Build HelloImGui for Glfw3+OpenGL3" OFF) # Use SDL2 + OpenGL3 -option(HELLOIMGUI_USE_SDL_OPENGL3 "Build HelloImGui for SDL+OpenGL3" OFF) +option(HELLOIMGUI_USE_SDL_OPENGL3 "Build HelloImGui for SDL2+OpenGL3" OFF) +# Use Glfw3 + Metal (Apple only) +option(HELLOIMGUI_USE_GLFW_METAL "Build HelloImGui for Glfw3+Metal" OFF) # Use SDL2 + Metal (Apple only) -option(HELLOIMGUI_USE_SDL_METAL "Build HelloImGui for SDL+Metal" OFF) +option(HELLOIMGUI_USE_SDL_METAL "Build HelloImGui for SDL2+Metal" OFF) # Note: Metal and OpenGl3 are mutually exclusive! diff --git a/src/hello_imgui/CMakeLists.txt b/src/hello_imgui/CMakeLists.txt index 8ee615d0..8ba82191 100644 --- a/src/hello_imgui/CMakeLists.txt +++ b/src/hello_imgui/CMakeLists.txt @@ -111,14 +111,10 @@ function(him_sanity_checks) set(backend_message " HelloImGui: no backend selected! In order to select your own backend, use one of the cmake options below: - -DHELLOIMGUI_WITH_GLFW=ON # To download and build glfw automatically - -DHELLOIMGUI_WITH_SDL=ON # To download and build SDL automatically - -DHELLOIMGUI_USE_GLFW_OPENGL3=ON # To use your own version of GLFW (it should be findable via find_package(glfw3)) - -DHELLOIMGUI_USE_SDL_OPENGL3=ON # To use your own version of SDL (it should be findable via find_package(SDL2)) - -DHELLOIMGUI_USE_SDL_METAL=ON # To use SDL2 + Metal - - (Note: under Linux, it is advised to use system-wide libraries, and not to use - -DHELLOIMGUI_WITH_GLFW=ON or -DHELLOIMGUI_WITH_SDL=ON) + -DHELLOIMGUI_USE_GLFW_OPENGL3=ON # Glfw3 + OpenGL3 + -DHELLOIMGUI_USE_SDL_OPENGL3=ON # SDL2 + OpenGL3 + -DHELLOIMGUI_USE_GLFW_METAL # Glfw3 + Metal + -DHELLOIMGUI_USE_SDL_METAL=ON # SDL2 + Metal ") message(STATUS "${backend_message}") @@ -134,6 +130,7 @@ function(_him_check_if_no_backend_selected) if (NOT HELLOIMGUI_USE_SDL_OPENGL3 AND NOT HELLOIMGUI_USE_GLFW_OPENGL3 AND NOT HELLOIMGUI_USE_SDL_METAL + AND NOT HELLOIMGUI_USE_GLFW_METAL ) set(HELLOIMGUI_NO_BACKEND_SELECTED ON CACHE INTERNAL "") endif() @@ -179,6 +176,7 @@ function(_him_try_select_glfw_if_no_backend_selected) endif() endfunction() + ################################################################################################### # Apple related options: API = him_add_apple_options ################################################################################################### @@ -274,6 +272,7 @@ function(him_add_android_options) endif() endfunction() + ################################################################################################### # Emscripten related options: API = him_add_emscripten_options ################################################################################################### @@ -323,6 +322,7 @@ function(_him_link_opengles_sdl target) ) endfunction() + ################################################################################################### # Metal Rendering backend: API = him_use_metal_backend ################################################################################################### @@ -337,6 +337,7 @@ function(him_use_metal_backend target) "-framework Metal -framework MetalKit -framework QuartzCore") endfunction() + ################################################################################################### # SDL Windowing backend: API = him_use_sdl2_backend ################################################################################################### @@ -551,6 +552,13 @@ function(him_main) target_compile_definitions(${helloimgui_target} PUBLIC HELLOIMGUI_USE_SDL_METAL) endif() + if(HELLOIMGUI_USE_GLFW_METAL) + him_use_metal_backend(${helloimgui_target}) + him_use_glfw_backend(${helloimgui_target}) + target_compile_definitions(${helloimgui_target} PUBLIC HELLOIMGUI_USE_GLFW_METAL) + endif() + + if(HELLOIMGUI_HAS_METAL AND HELLOIMGUI_HAS_OPENGL) message(FATAL_ERROR "HelloImGui: cannot have both Metal and OpenGL backends at the same time") endif() diff --git a/src/hello_imgui/internal/backend_impls/rendering_metal.h b/src/hello_imgui/internal/backend_impls/rendering_metal.h index 3881b387..bb6d840b 100644 --- a/src/hello_imgui/internal/backend_impls/rendering_metal.h +++ b/src/hello_imgui/internal/backend_impls/rendering_metal.h @@ -9,21 +9,27 @@ struct SDL_Renderer; struct SDL_Window; #endif +#ifdef HELLOIMGUI_USE_GLFW3 +struct GLFWwindow; +#endif + #include "hello_imgui/internal/backend_impls/rendering_callbacks.h" namespace HelloImGui { - RenderingCallbacks CreateBackendCallbacks_Metal(); #ifdef HELLOIMGUI_USE_SDL2 - void PrepareSdLForMetal_WithWindow_PreImGuiInit(SDL_Window* window); - void PrepareSdLForMetal_PosImGuiInit(); + RenderingCallbacks CreateBackendCallbacks_SdlMetal(); + + void PrepareSdlForMetal_WithWindow_PreImGuiInit(SDL_Window* window); + void PrepareSdlForMetal_PosImGuiInit(); void SwapSdlMetalBuffers(); struct SdlMetalGlobals { SDL_Window* sdlWindow = nullptr; SDL_Renderer* sdlRenderer = nullptr; + CAMetalLayer* caMetalLayer = nullptr; id caMetalDrawable = nullptr; id mtlCommandBuffer = nullptr; @@ -34,6 +40,31 @@ namespace HelloImGui SdlMetalGlobals& GetSdlMetalGlobals(); #endif + +#ifdef HELLOIMGUI_USE_GLFW3 + RenderingCallbacks CreateBackendCallbacks_GlfwMetal(); + + void PrepareGlfwForMetal_WithWindow_PreImGuiInit(GLFWwindow* window); + void PrepareGlfwForMetal_PosImGuiInit(); + void SwapGlfwMetalBuffers(); + + struct GlfwMetalGlobals + { + GLFWwindow* glfwWindow = nullptr; + + id mtlDevice = nullptr; + + CAMetalLayer* caMetalLayer = nullptr; + id caMetalDrawable = nullptr; + id mtlCommandBuffer = nullptr; + id mtlCommandQueue = nullptr; + MTLRenderPassDescriptor* mtlRenderPassDescriptor = nullptr; + id mtlRenderCommandEncoder = nullptr; + }; + + GlfwMetalGlobals& GetGlfwMetalGlobals(); +#endif + } #endif // HELLOIMGUI_HAS_METAL diff --git a/src/hello_imgui/internal/backend_impls/rendering_metal_glfw.mm b/src/hello_imgui/internal/backend_impls/rendering_metal_glfw.mm new file mode 100644 index 00000000..9b90d887 --- /dev/null +++ b/src/hello_imgui/internal/backend_impls/rendering_metal_glfw.mm @@ -0,0 +1,122 @@ +#ifdef HELLOIMGUI_HAS_METAL +#ifdef HELLOIMGUI_USE_GLFW3 + +#include "rendering_metal.h" + +#import +#import +#include +#include + +#include "hello_imgui/hello_imgui.h" + +#define GLFW_INCLUDE_NONE +#define GLFW_EXPOSE_NATIVE_COCOA +#include +#include +#include + + +namespace HelloImGui +{ + GlfwMetalGlobals gGlfwMetalGlobals; + + void PrepareGlfwForMetal_WithWindow_PreImGuiInit(GLFWwindow* glfwWindow) + { + gGlfwMetalGlobals.glfwWindow = glfwWindow; +// gGlfwMetalGlobals.sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); +// if (gGlfwMetalGlobals.sdlRenderer == nullptr) +// { +// bool Error_SdlCreateRenderer_For_Metal = false; +// IM_ASSERT(Error_SdlCreateRenderer_For_Metal); +// exit(-3); +// } + + // Setup Platform/Renderer backends +// gGlfwMetalGlobals.caMetalLayer = (__bridge CAMetalLayer*)SDL_RenderGetMetalLayer(gGlfwMetalGlobals.sdlRenderer); +// gGlfwMetalGlobals.caMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm; + + gGlfwMetalGlobals.mtlDevice = MTLCreateSystemDefaultDevice(); + gGlfwMetalGlobals.mtlCommandQueue = [gGlfwMetalGlobals.mtlDevice newCommandQueue]; + } + + void PrepareGlfwForMetal_PosImGuiInit() + { + ImGui_ImplGlfw_InitForOther(gGlfwMetalGlobals.glfwWindow, true); + ImGui_ImplMetal_Init(gGlfwMetalGlobals.mtlDevice); + + NSWindow *nswin = glfwGetCocoaWindow(gGlfwMetalGlobals.glfwWindow); + gGlfwMetalGlobals.caMetalLayer = [CAMetalLayer layer]; + gGlfwMetalGlobals.caMetalLayer.device = gGlfwMetalGlobals.mtlDevice; + gGlfwMetalGlobals.caMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm; + nswin.contentView.layer = gGlfwMetalGlobals.caMetalLayer; + nswin.contentView.wantsLayer = YES; + + gGlfwMetalGlobals.mtlRenderPassDescriptor = [MTLRenderPassDescriptor new]; + } + + void SwapGlfwMetalBuffers() + { + [gGlfwMetalGlobals.mtlRenderCommandEncoder popDebugGroup]; + [gGlfwMetalGlobals.mtlRenderCommandEncoder endEncoding]; + + [gGlfwMetalGlobals.mtlCommandBuffer presentDrawable:gGlfwMetalGlobals.caMetalDrawable]; + [gGlfwMetalGlobals.mtlCommandBuffer commit]; + } + + RenderingCallbacks CreateBackendCallbacks_GlfwMetal() + { + RenderingCallbacks callbacks; + + callbacks.Impl_NewFrame_3D = [] + { + auto Vec4_To_Array = [](ImVec4 v) { return std::array{ v.x, v.y, v.z, v.w }; }; + + int width, height; + glfwGetFramebufferSize(gGlfwMetalGlobals.glfwWindow, &width, &height); + gGlfwMetalGlobals.caMetalLayer.drawableSize = CGSizeMake(width, height); + gGlfwMetalGlobals.caMetalDrawable = [gGlfwMetalGlobals.caMetalLayer nextDrawable]; + + gGlfwMetalGlobals.mtlCommandBuffer = [gGlfwMetalGlobals.mtlCommandQueue commandBuffer]; + auto clearColor = Vec4_To_Array(HelloImGui::GetRunnerParams()->imGuiWindowParams.backgroundColor); + gGlfwMetalGlobals.mtlRenderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(clearColor[0] * clearColor[3], clearColor[1] * clearColor[3], clearColor[2] * clearColor[3], clearColor[3]); + gGlfwMetalGlobals.mtlRenderPassDescriptor.colorAttachments[0].texture = gGlfwMetalGlobals.caMetalDrawable.texture; + gGlfwMetalGlobals.mtlRenderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; + gGlfwMetalGlobals.mtlRenderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; + gGlfwMetalGlobals.mtlRenderCommandEncoder = [ + gGlfwMetalGlobals.mtlCommandBuffer renderCommandEncoderWithDescriptor:gGlfwMetalGlobals.mtlRenderPassDescriptor]; + [gGlfwMetalGlobals.mtlRenderCommandEncoder pushDebugGroup:@"ImGui demo"]; + + // Start the Dear ImGui frame + ImGui_ImplMetal_NewFrame(gGlfwMetalGlobals.mtlRenderPassDescriptor); + ImGui_ImplGlfw_NewFrame(); + }; + + callbacks.Impl_RenderDrawData_To_3D = [] + { + ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), gGlfwMetalGlobals.mtlCommandBuffer, gGlfwMetalGlobals.mtlRenderCommandEncoder); + }; + + // Not implemented for Metal + //callbacks.Impl_ScreenshotRgb = []() { ...;}; + + // This is done at Impl_NewFrame_3D + callbacks.Impl_Frame_3D_ClearColor = [](ImVec4 clearColor) { }; + + callbacks.Impl_Shutdown_3D = [] + { + ImGui_ImplMetal_Shutdown(); + }; + return callbacks; + } + + GlfwMetalGlobals& GetGlfwMetalGlobals() + { + return gGlfwMetalGlobals; + } + + +} // namespace HelloImGui + +#endif // HELLOIMGUI_USE_GLFW3 +#endif // HELLOIMGUI_HAS_METAL \ No newline at end of file diff --git a/src/hello_imgui/internal/backend_impls/rendering_metal.mm b/src/hello_imgui/internal/backend_impls/rendering_metal_sdl.mm similarity index 94% rename from src/hello_imgui/internal/backend_impls/rendering_metal.mm rename to src/hello_imgui/internal/backend_impls/rendering_metal_sdl.mm index 3bfba357..256cb190 100644 --- a/src/hello_imgui/internal/backend_impls/rendering_metal.mm +++ b/src/hello_imgui/internal/backend_impls/rendering_metal_sdl.mm @@ -1,4 +1,5 @@ #ifdef HELLOIMGUI_HAS_METAL +#ifdef HELLOIMGUI_USE_SDL2 #include "rendering_metal.h" #import @@ -10,19 +11,15 @@ #include "hello_imgui/internal/stb_image.h" #include "hello_imgui/hello_imgui.h" -#ifdef HELLOIMGUI_USE_SDL2 #include #include -#endif namespace HelloImGui { - #ifdef HELLOIMGUI_USE_SDL2 - SdlMetalGlobals gSdlMetalGlobals; - void PrepareSdLForMetal_WithWindow_PreImGuiInit(SDL_Window* sdlWindow) + void PrepareSdlForMetal_WithWindow_PreImGuiInit(SDL_Window* sdlWindow) { gSdlMetalGlobals.sdlWindow = sdlWindow; gSdlMetalGlobals.sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); @@ -38,7 +35,7 @@ void PrepareSdLForMetal_WithWindow_PreImGuiInit(SDL_Window* sdlWindow) gSdlMetalGlobals.caMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm; } - void PrepareSdLForMetal_PosImGuiInit() + void PrepareSdlForMetal_PosImGuiInit() { ImGui_ImplMetal_Init(gSdlMetalGlobals.caMetalLayer.device); ImGui_ImplSDL2_InitForMetal(gSdlMetalGlobals.sdlWindow); @@ -56,7 +53,7 @@ void SwapSdlMetalBuffers() [gSdlMetalGlobals.mtlCommandBuffer commit]; } - RenderingCallbacks CreateBackendCallbacks_Metal() + RenderingCallbacks CreateBackendCallbacks_SdlMetal() { RenderingCallbacks callbacks; @@ -108,10 +105,7 @@ RenderingCallbacks CreateBackendCallbacks_Metal() return gSdlMetalGlobals; } - -#endif // #ifdef HELLOIMGUI_USE_SDL2 - - } // namespace HelloImGui +#endif // HELLOIMGUI_USE_SDL2 #endif // HELLOIMGUI_HAS_METAL \ No newline at end of file diff --git a/src/hello_imgui/internal/backend_impls/runner_glfw3.cpp b/src/hello_imgui/internal/backend_impls/runner_glfw3.cpp index 6b05a8e4..d2b7c906 100644 --- a/src/hello_imgui/internal/backend_impls/runner_glfw3.cpp +++ b/src/hello_imgui/internal/backend_impls/runner_glfw3.cpp @@ -7,10 +7,12 @@ #include "opengl_setup_helper/opengl_screenshot.h" #include "rendering_opengl3.h" #endif +#ifdef HELLOIMGUI_HAS_METAL +#include "rendering_metal.h" +#endif #include "hello_imgui/hello_imgui.h" #include "hello_imgui/internal/stb_image.h" -#include "hello_imgui/hello_imgui_assets.h" #include "backend_window_helper/glfw_window_helper.h" #include "hello_imgui/hello_imgui_error.h" @@ -18,12 +20,13 @@ #include #include #include -#include + namespace HelloImGui { +#ifdef HELLOIMGUI_HAS_OPENGL BackendApi::OpenGlSetupGlfw gOpenGlHelper; - +#endif static void glfw_error_callback(int error, const char* description) { @@ -49,13 +52,25 @@ namespace HelloImGui IM_ASSERT(glfwInitSuccess); } + void RunnerGlfw3::Impl_InitBackend_PostImGuiInit() + { +#ifdef HELLOIMGUI_HAS_METAL + PrepareGlfwForMetal_PosImGuiInit(); +#endif + } void RunnerGlfw3::Impl_CreateWindow() { BackendApi::BackendOptions backendOptions; +#ifdef HELLOIMGUI_HAS_METAL + backendOptions.backend3DMode = BackendApi::Backend3dMode::Metal; +#endif mWindow = mBackendWindowHelper->CreateWindow(params.appWindowParams, backendOptions); params.backendPointers.glfwWindow = mWindow; +#ifdef HELLOIMGUI_HAS_METAL + PrepareGlfwForMetal_WithWindow_PreImGuiInit((GLFWwindow *)mWindow); +#endif } void RunnerGlfw3::Impl_PollEvents() @@ -92,7 +107,15 @@ namespace HelloImGui glfwTerminate(); } - void RunnerGlfw3::Impl_SwapBuffers() { glfwSwapBuffers((GLFWwindow *)mWindow); } + void RunnerGlfw3::Impl_SwapBuffers() + { +#ifdef HELLOIMGUI_HAS_OPENGL + glfwSwapBuffers((GLFWwindow *)mWindow); +#endif +#ifdef HELLOIMGUI_HAS_METAL + SwapGlfwMetalBuffers(); +#endif + } void RunnerGlfw3::Impl_SetWindowIcon() { @@ -152,6 +175,16 @@ namespace HelloImGui void RunnerGlfw3::Impl_InitGlLoader() { gOpenGlHelper.InitGlLoader(); } #endif // #ifdef HELLOIMGUI_HAS_OPENGL +#ifdef HELLOIMGUI_HAS_METAL + void RunnerGlfw3::Impl_InitRenderBackendCallbacks() + { + mRenderingBackendCallbacks = CreateBackendCallbacks_GlfwMetal(); + } + void RunnerGlfw3::Impl_LinkWindowingToRenderingBackend() + { + } +#endif + } // namespace HelloImGui #endif // #ifdef HELLOIMGUI_USE_GLFW diff --git a/src/hello_imgui/internal/backend_impls/runner_glfw3.h b/src/hello_imgui/internal/backend_impls/runner_glfw3.h index a473f899..053f83f7 100644 --- a/src/hello_imgui/internal/backend_impls/runner_glfw3.h +++ b/src/hello_imgui/internal/backend_impls/runner_glfw3.h @@ -18,6 +18,7 @@ class RunnerGlfw3 : public AbstractRunner // Methods related to the Windowing backend (SDL, Glfw, ...) // void Impl_InitBackend() override; + void Impl_InitBackend_PostImGuiInit(); void Impl_CreateWindow() override; void Impl_PollEvents() override; void Impl_NewFrame_Backend() override; diff --git a/src/hello_imgui/internal/backend_impls/runner_sdl2.cpp b/src/hello_imgui/internal/backend_impls/runner_sdl2.cpp index 6e4c3c4b..272f24a3 100644 --- a/src/hello_imgui/internal/backend_impls/runner_sdl2.cpp +++ b/src/hello_imgui/internal/backend_impls/runner_sdl2.cpp @@ -64,9 +64,9 @@ namespace HelloImGui void RunnerSdl2::Impl_InitBackend_PostImGuiInit() { - #ifdef HELLOIMGUI_HAS_METAL - PrepareSdLForMetal_PosImGuiInit(); - #endif +#ifdef HELLOIMGUI_HAS_METAL + PrepareSdlForMetal_PosImGuiInit(); +#endif } void RunnerSdl2::Impl_CreateWindow() @@ -79,7 +79,7 @@ namespace HelloImGui mWindow = mBackendWindowHelper->CreateWindow(params.appWindowParams, backendOptions); params.backendPointers.sdlWindow = mWindow; #ifdef HELLOIMGUI_HAS_METAL - PrepareSdLForMetal_WithWindow_PreImGuiInit((SDL_Window *)mWindow); + PrepareSdlForMetal_WithWindow_PreImGuiInit((SDL_Window *)mWindow); #endif } @@ -259,7 +259,7 @@ namespace HelloImGui #ifdef HELLOIMGUI_HAS_METAL void RunnerSdl2::Impl_InitRenderBackendCallbacks() { - mRenderingBackendCallbacks = CreateBackendCallbacks_Metal(); + mRenderingBackendCallbacks = CreateBackendCallbacks_SdlMetal(); } void RunnerSdl2::Impl_LinkWindowingToRenderingBackend() { diff --git a/src/hello_imgui/internal/image_from_asset.cpp b/src/hello_imgui/internal/image_from_asset.cpp index f26e9bce..4d8c3606 100644 --- a/src/hello_imgui/internal/image_from_asset.cpp +++ b/src/hello_imgui/internal/image_from_asset.cpp @@ -55,12 +55,16 @@ namespace HelloImGui { void ImageFromAsset(const char *assetPath, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f)); ImGui::Text("ImageFromAsset requires OpenGL"); + ImGui::PopStyleColor(); } bool ImageButtonFromAsset(const char *assetPath, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f)); ImGui::Text("ButtonFromAsset requires OpenGL"); + ImGui::PopStyleColor(); return false; }