Pārlūkot izejas kodu

add low level ImGui backend that matches the other backends.

Jeffery Myers 1 gadu atpakaļ
vecāks
revīzija
a07b514fe2
6 mainītis faili ar 429 papildinājumiem un 153 dzēšanām
  1. 2 1
      README.md
  2. 124 0
      examples/imgui_style_example.cpp
  3. 53 0
      imgui_impl_raylib.h
  4. 20 0
      premake5.lua
  5. 217 149
      rlImGui.cpp
  6. 13 3
      rlImGui.h

+ 2 - 1
README.md

@@ -71,4 +71,5 @@ bool rlImGuiImageButtonSize(const char* name, const Texture* image, struct ImVec
 ImGui is a C++ library, so rlImGui uses C++ to create the backend and integration with Raylib.
 The rlImGui.h API only uses features that are common to C and C++, so rlImGui can be built as a static library and used by pure C code. Users of ImGui who wish to use pure C must use an ImGui wrapper, such as [https://github.com/cimgui/cimgui].
 
-
+# Low level API
+If you would like more controll over the ImGui Backend, you can use the low level API that is found in imgui_impl_raylib.h. This is API follows the patterns of other ImGui backends and does not do automatic context management. An example of it's use can be found in imgui_style_example.cpp 

+ 124 - 0
examples/imgui_style_example.cpp

@@ -0,0 +1,124 @@
+// Dear ImGui: standalone example application for Raylib with OpenGL
+// (Raylib is a simple learning library for game development)
+
+// 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 "imgui.h"
+#include "imgui_impl_raylib.h"
+#include "raylib.h"
+
+// Main code
+int main(int, char**)
+{
+    // Setup raylib window
+    SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI);
+    InitWindow(1280, 720, "Dear ImGui Raylib(OpenGL) example");
+ 
+    // Setup Dear ImGui context
+    ImGui::CreateContext();
+    ImGuiIO& io = ImGui::GetIO(); (void)io;
+    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
+    io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
+
+    // Setup Dear ImGui style
+    ImGui::StyleColorsDark();
+    //ImGui::StyleColorsLight();
+
+    // Setup Platform/Renderer backends
+    ImGui_ImplRaylib_Init();
+
+    // Load Fonts
+    // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+    // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+    // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
+    // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
+    // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
+    // - Read 'docs/FONTS.md' for more instructions and details.
+    // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
+    //io.Fonts->AddFontDefault();
+    //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
+    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
+    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
+    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
+    //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese());
+    //IM_ASSERT(font != nullptr);
+
+    // Our state
+    bool show_demo_window = true;
+    bool show_another_window = false;
+    ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
+
+    // Main loop
+    bool done = false;
+    while (!done)
+    {
+        // Poll and handle events (inputs, window resize, etc.)
+        // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
+        // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
+        // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
+        // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
+        ImGui_ImplRaylib_ProcessEvents();
+
+        // Start the Dear ImGui frame
+        ImGui_ImplRaylib_NewFrame();
+        ImGui::NewFrame();
+
+        // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
+        if (show_demo_window)
+            ImGui::ShowDemoWindow(&show_demo_window);
+
+        // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
+        {
+            static float f = 0.0f;
+            static int counter = 0;
+
+            ImGui::Begin("Hello, world!");                          // Create a window called "Hello, world!" and append into it.
+
+            ImGui::Text("This is some useful text.");               // Display some text (you can use a format strings too)
+            ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state
+            ImGui::Checkbox("Another Window", &show_another_window);
+
+            ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float using a slider from 0.0f to 1.0f
+            ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
+
+            if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated)
+                counter++;
+            ImGui::SameLine();
+            ImGui::Text("counter = %d", counter);
+
+            ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
+            ImGui::End();
+        }
+
+        // 3. Show another simple window.
+        if (show_another_window)
+        {
+            ImGui::Begin("Another Window", &show_another_window);   // 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"))
+                show_another_window = false;
+            ImGui::End();
+        }
+
+
+        // Rendering
+        ImGui::Render();
+        BeginDrawing();
+        ClearBackground(Color{ (unsigned char)(clear_color.x * 255), (unsigned char)(clear_color.y * 255),(unsigned char)(clear_color.z * 255),(unsigned char)(clear_color.w * 255) });
+        ImGui_ImplRaylib_RenderDrawData(ImGui::GetDrawData());
+        EndDrawing();
+
+        done = WindowShouldClose();
+    }
+    // Cleanup
+    ImGui_ImplRaylib_Shutdown();
+    ImGui::DestroyContext();
+
+    CloseWindow();
+
+    return 0;
+}

+ 53 - 0
imgui_impl_raylib.h

@@ -0,0 +1,53 @@
+/**********************************************************************************************
+*
+*   raylibExtras * Utilities and Shared Components for Raylib
+*
+*   rlImGui * basic ImGui integration
+*
+*   LICENSE: ZLIB
+*
+*   Copyright (c) 2023 Jeffery Myers
+*
+*   Permission is hereby granted, free of charge, to any person obtaining a copy
+*   of this software and associated documentation files (the "Software"), to deal
+*   in the Software without restriction, including without limitation the rights
+*   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+*   copies of the Software, and to permit persons to whom the Software is
+*   furnished to do so, subject to the following conditions:
+*
+*   The above copyright notice and this permission notice shall be included in all
+*   copies or substantial portions of the Software.
+*
+*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+*   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+*   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+*   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+*   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+*   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+*   SOFTWARE.
+*
+**********************************************************************************************/
+
+// dear imgui: Platform Backend for Raylib
+// (Info: Raylib is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc. using OpenGL)
+// This is is the low level ImGui backend for raylib, a higher level API that matches the raylib API can be found in rlImGui.h
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// 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
+
+#pragma once
+#include "imgui.h"      // IMGUI_IMPL_API
+#ifndef IMGUI_DISABLE
+
+IMGUI_IMPL_API bool ImGui_ImplRaylib_Init();
+IMGUI_IMPL_API void ImGui_ImplRaylib_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplRaylib_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplRaylib_RenderDrawData(ImDrawData* draw_data);
+IMGUI_IMPL_API bool ImGui_ImplRaylib_ProcessEvents();
+
+#endif // #ifndef IMGUI_DISABLE

+ 20 - 0
premake5.lua

@@ -150,4 +150,24 @@ project "editor"
 
     filter "action:vs*"
 		debugdir "$(SolutionDir)"	
+        
+        
+project "imgui_style_example"
+	kind "ConsoleApp"
+	language "C++"
+	location "_build"
+	targetdir "_bin/%{cfg.buildcfg}"
+	
+	vpaths 
+	{
+		["Header Files"] = { "examples/**.h"},
+		["Source Files"] = {"examples/**.cpp", "examples/**.c"},
+	}
+	files {"examples/imgui_style_example.cpp"}
+	link_raylib()
+	links {"rlImGui"}
+	includedirs {"./", "imgui", "imgui-master" }
+		
+    filter "action:vs*"
+		debugdir "$(SolutionDir)"	
 	

+ 217 - 149
rlImGui.cpp

@@ -29,7 +29,8 @@
 **********************************************************************************************/
 #include "rlImGui.h"
 
-#include "imgui.h"
+#include "imgui_impl_raylib.h"
+
 #include "raylib.h"
 #include "rlgl.h"
 
@@ -44,8 +45,6 @@
 #include "extras/FA6FreeSolidFontData.h"
 #endif
 
-static Texture2D FontTexture;
-
 static ImGuiMouseCursor CurrentMouseCursor = ImGuiMouseCursor_COUNT;
 static MouseCursor MouseCursorMap[ImGuiMouseCursor_COUNT];
 
@@ -65,17 +64,41 @@ bool rlImGuiIsShiftDown() { return IsKeyDown(KEY_RIGHT_SHIFT) || IsKeyDown(KEY_L
 bool rlImGuiIsAltDown() { return IsKeyDown(KEY_RIGHT_ALT) || IsKeyDown(KEY_LEFT_ALT); }
 bool rlImGuiIsSuperDown() { return IsKeyDown(KEY_RIGHT_SUPER) || IsKeyDown(KEY_LEFT_SUPER); }
 
-static const char* rlImGuiGetClipText(void*) 
+void ReloadFonts()
+{
+	ImGuiIO& io = ImGui::GetIO();
+	unsigned char* pixels = nullptr;
+
+	int width;
+	int height;
+	io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, nullptr);
+	Image image = GenImageColor(width, height, BLANK);
+	memcpy(image.data, pixels, width * height * 4);
+
+	Texture2D* fontTexture = (Texture2D*)io.Fonts->TexID;
+	if (fontTexture && fontTexture->id != 0)
+	{
+		UnloadTexture(*fontTexture);
+		MemFree(fontTexture);
+	}
+
+	fontTexture = (Texture2D*)MemAlloc(sizeof(Texture2D));
+	*fontTexture = LoadTextureFromImage(image);
+	UnloadImage(image);
+	io.Fonts->TexID = fontTexture;
+}
+
+static const char* GetClipTextCallback(void*) 
 {
     return GetClipboardText();
 }
 
-static void rlImGuiSetClipText(void*, const char* text)
+static void SetClipTextCallback(void*, const char* text)
 {
     SetClipboardText(text);
 }
 
-static void rlImGuiNewFrame(float deltaTime)
+static void ImGuiNewFrame(float deltaTime)
 {
     ImGuiIO& io = ImGui::GetIO();
 
@@ -149,63 +172,7 @@ static void rlImGuiNewFrame(float deltaTime)
     }
 }
 
-static void rlImGuiEvents()
-{
-    ImGuiIO& io = ImGui::GetIO();
-
-    bool focused = IsWindowFocused();
-    if (focused != LastFrameFocused)
-        io.AddFocusEvent(focused);
-    LastFrameFocused = focused;
-
-    // handle the modifyer key events so that shortcuts work
-    bool ctrlDown = rlImGuiIsControlDown();
-    if (ctrlDown != LastControlPressed)
-        io.AddKeyEvent(ImGuiMod_Ctrl, ctrlDown);
-    LastControlPressed = ctrlDown;
-
-    bool shiftDown = rlImGuiIsShiftDown();
-    if (shiftDown != LastShiftPressed)
-        io.AddKeyEvent(ImGuiMod_Shift, shiftDown);
-    LastShiftPressed = shiftDown;
-
-    bool altDown = rlImGuiIsAltDown();
-    if (altDown != LastAltPressed)
-        io.AddKeyEvent(ImGuiMod_Alt, altDown);
-    LastAltPressed = altDown;
-
-    bool superDown = rlImGuiIsSuperDown();
-    if (superDown != LastSuperPressed)
-        io.AddKeyEvent(ImGuiMod_Super, superDown);
-    LastSuperPressed = superDown;
-
-    // get the pressed keys, they are in event order
-    int keyId = GetKeyPressed();
-    while (keyId != 0)
-    {
-        auto keyItr = RaylibKeyMap.find(KeyboardKey(keyId));
-        if (keyItr != RaylibKeyMap.end())
-            io.AddKeyEvent(keyItr->second, true);
-        keyId = GetKeyPressed();
-    }
-
-    // look for any keys that were down last frame and see if they were down and are released
-    for (const auto keyItr : RaylibKeyMap)
-    {
-        if (IsKeyReleased(keyItr.first))
-            io.AddKeyEvent(keyItr.second, false);
-    }
-
-    // add the text input in order
-    unsigned int pressed = GetCharPressed();
-    while (pressed != 0)
-    {
-        io.AddInputCharacter(pressed);
-        pressed = GetCharPressed();
-    }
-}
-
-static void rlImGuiTriangleVert(ImDrawVert& idx_vert)
+static void ImGuiTriangleVert(ImDrawVert& idx_vert)
 {
     Color* c;
     c = (Color*)&idx_vert.col;
@@ -214,7 +181,7 @@ static void rlImGuiTriangleVert(ImDrawVert& idx_vert)
     rlVertex2f(idx_vert.pos.x, idx_vert.pos.y);
 }
 
-static void rlImGuiRenderTriangles(unsigned int count, int indexStart, const ImVector<ImDrawIdx>& indexBuffer, const ImVector<ImDrawVert>& vertBuffer, void* texturePtr)
+static void ImGuiRenderTriangles(unsigned int count, int indexStart, const ImVector<ImDrawIdx>& indexBuffer, const ImVector<ImDrawVert>& vertBuffer, void* texturePtr)
 {
     if (count < 3)
         return;
@@ -242,9 +209,9 @@ static void rlImGuiRenderTriangles(unsigned int count, int indexStart, const ImV
         ImDrawVert vertexB = vertBuffer[indexB];
         ImDrawVert vertexC = vertBuffer[indexC];
 
-        rlImGuiTriangleVert(vertexA);
-        rlImGuiTriangleVert(vertexB);
-        rlImGuiTriangleVert(vertexC);
+        ImGuiTriangleVert(vertexA);
+        ImGuiTriangleVert(vertexB);
+        ImGuiTriangleVert(vertexC);
     }
     rlEnd();
 }
@@ -259,36 +226,7 @@ static void EnableScissor(float x, float y, float width, float height)
         (int)(height * io.DisplayFramebufferScale.y));
 }
 
-static void rlRenderData(ImDrawData* data)
-{
-    rlDrawRenderBatchActive();
-    rlDisableBackfaceCulling();
-
-    for (int l = 0; l < data->CmdListsCount; ++l)
-    {
-        const ImDrawList* commandList = data->CmdLists[l];
-
-        for (const auto& cmd : commandList->CmdBuffer)
-        {
-            EnableScissor(cmd.ClipRect.x - data->DisplayPos.x, cmd.ClipRect.y - data->DisplayPos.y, cmd.ClipRect.z - (cmd.ClipRect.x - data->DisplayPos.x), cmd.ClipRect.w - (cmd.ClipRect.y - data->DisplayPos.y));
-            if (cmd.UserCallback != nullptr)
-            {
-                cmd.UserCallback(commandList, &cmd);
-
-                continue;
-            }
-
-            rlImGuiRenderTriangles(cmd.ElemCount, cmd.IdxOffset, commandList->IdxBuffer, commandList->VtxBuffer, cmd.TextureId);
-            rlDrawRenderBatchActive();
-        }
-    }
-
-    rlSetTexture(0);
-    rlDisableScissorTest();
-    rlEnableBackfaceCulling();
-}
-
-void SetupMouseCursors()
+static void SetupMouseCursors()
 {
     MouseCursorMap[ImGuiMouseCursor_Arrow] = MOUSE_CURSOR_ARROW;
     MouseCursorMap[ImGuiMouseCursor_TextInput] = MOUSE_CURSOR_IBEAM;
@@ -301,28 +239,53 @@ void SetupMouseCursors()
     MouseCursorMap[ImGuiMouseCursor_NotAllowed] = MOUSE_CURSOR_NOT_ALLOWED;
 }
 
-void rlImGuiEndInitImGui()
+void SetupFontAwesome()
 {
-    ImGui::SetCurrentContext(GlobalContext);
+#ifndef NO_FONT_AWESOME
+	static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
+	ImFontConfig icons_config;
+	icons_config.MergeMode = true;
+	icons_config.PixelSnapH = true;
+	icons_config.FontDataOwnedByAtlas = false;
 
-    SetupMouseCursors();
+	icons_config.GlyphRanges = icons_ranges;
 
     ImGuiIO& io = ImGui::GetIO();
-    io.BackendPlatformName = "imgui_impl_raylib";
 
-    io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
+	io.Fonts->AddFontFromMemoryCompressedTTF((void*)fa_solid_900_compressed_data, fa_solid_900_compressed_size, FONT_AWESOME_ICON_SIZE, &icons_config, icons_ranges);
+#endif
+
+}
+
+void SetupBackend()
+{
+    ImGuiIO& io = ImGui::GetIO();
+	io.BackendPlatformName = "imgui_impl_raylib";
 
-    io.MousePos = ImVec2(0, 0);
+	io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
 
-    io.SetClipboardTextFn = rlImGuiSetClipText;
-    io.GetClipboardTextFn = rlImGuiGetClipText;
+	io.MousePos = ImVec2(0, 0);
 
-    io.ClipboardUserData = nullptr;
+	io.SetClipboardTextFn = SetClipTextCallback;
+	io.GetClipboardTextFn = GetClipTextCallback;
 
-    rlImGuiReloadFonts();
+	io.ClipboardUserData = nullptr;
 }
 
-void rlSetupKeymap()
+void rlImGuiEndInitImGui()
+{
+    ImGui::SetCurrentContext(GlobalContext);
+
+    SetupFontAwesome();
+
+    SetupMouseCursors();
+
+    SetupBackend();
+
+    ReloadFonts();
+}
+
+static void SetupKeymap()
 {
     if (!RaylibKeyMap.empty())
         return;
@@ -435,20 +398,28 @@ void rlSetupKeymap()
     RaylibKeyMap[KEY_KP_EQUAL] = ImGuiKey_KeypadEqual;
 }
 
+static void SetupGlobals()
+{
+	LastFrameFocused = IsWindowFocused();
+	LastControlPressed = false;
+	LastShiftPressed = false;
+	LastAltPressed = false;
+	LastSuperPressed = false;
+
+}
+
 void rlImGuiBeginInitImGui()
 {
+    SetupGlobals();
     GlobalContext = ImGui::CreateContext(nullptr);
-    rlSetupKeymap();
+    SetupKeymap();
+
+	ImGuiIO& io = ImGui::GetIO();
+	io.Fonts->AddFontDefault();
 }
 
 void rlImGuiSetup(bool dark)
 {
-    LastFrameFocused = IsWindowFocused();
-    LastControlPressed = false;
-    LastShiftPressed = false;
-    LastAltPressed = false;
-    LastSuperPressed = false;
-
     rlImGuiBeginInitImGui();
 
     if (dark)
@@ -456,20 +427,6 @@ void rlImGuiSetup(bool dark)
     else
         ImGui::StyleColorsLight();
 
-    ImGuiIO& io = ImGui::GetIO();
-    io.Fonts->AddFontDefault();
-
-#ifndef NO_FONT_AWESOME
-    static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
-    ImFontConfig icons_config;
-    icons_config.MergeMode = true;
-    icons_config.PixelSnapH = true;
-    icons_config.FontDataOwnedByAtlas = false;
-
-    icons_config.GlyphRanges = icons_ranges;
-    io.Fonts->AddFontFromMemoryCompressedTTF((void*)fa_solid_900_compressed_data, fa_solid_900_compressed_size, FONT_AWESOME_ICON_SIZE, &icons_config, icons_ranges);
-#endif
-
     rlImGuiEndInitImGui();
 }
 
@@ -477,33 +434,20 @@ void rlImGuiReloadFonts()
 {
     ImGui::SetCurrentContext(GlobalContext);
 
-    ImGuiIO& io = ImGui::GetIO();
-    unsigned char* pixels = nullptr;
-
-    int width;
-    int height;
-    io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, nullptr);
-    Image image = GenImageColor(width, height, BLANK);
-    memcpy(image.data, pixels, width * height * 4);
-
-    if (FontTexture.id != 0)
-        UnloadTexture(FontTexture);
-
-    FontTexture = LoadTextureFromImage(image);
-    UnloadImage(image);
-    io.Fonts->TexID = &FontTexture;
+    ReloadFonts();
 }
 
 void rlImGuiBegin()
 {
+    ImGui::SetCurrentContext(GlobalContext);
     rlImGuiBeginDelta(GetFrameTime());
 }
 
 void rlImGuiBeginDelta(float deltaTime)
 {
     ImGui::SetCurrentContext(GlobalContext);
-	rlImGuiNewFrame(deltaTime);
-	rlImGuiEvents();
+	ImGuiNewFrame(deltaTime);
+    ImGui_ImplRaylib_ProcessEvents();
 	ImGui::NewFrame();
 }
 
@@ -511,14 +455,14 @@ void rlImGuiEnd()
 {
     ImGui::SetCurrentContext(GlobalContext);
     ImGui::Render();
-    rlRenderData(ImGui::GetDrawData());
+    ImGui_ImplRaylib_RenderDrawData(ImGui::GetDrawData());
 }
 
 void rlImGuiShutdown()
 {
-    UnloadTexture(FontTexture);
+	ImGui::SetCurrentContext(GlobalContext);
+    ImGui_ImplRaylib_Shutdown();
 
-    ImGui::SetCurrentContext(GlobalContext);
     ImGui::DestroyContext();
 }
 
@@ -630,3 +574,127 @@ void rlImGuiImageRenderTextureFit(const RenderTexture* image, bool center)
 
     rlImGuiImageRect(&image->texture, sizeX, sizeY, Rectangle{ 0,0, float(image->texture.width), -float(image->texture.height) });
 }
+
+// raw ImGui backend API
+bool ImGui_ImplRaylib_Init()
+{
+    SetupGlobals();
+
+	SetupKeymap();
+
+	ImGuiIO& io = ImGui::GetIO();
+	io.Fonts->AddFontDefault();
+
+    SetupFontAwesome();
+
+	SetupMouseCursors();
+
+    SetupBackend();
+
+    ReloadFonts();
+
+    return true;
+}
+
+void ImGui_ImplRaylib_Shutdown()
+{
+    ImGuiIO& io =ImGui::GetIO();
+    Texture2D* fontTexture = (Texture2D*)io.Fonts->TexID;
+
+    if (fontTexture && fontTexture->id != 0)
+	UnloadTexture(*fontTexture);
+
+    io.Fonts->TexID = 0;
+}
+
+void ImGui_ImplRaylib_NewFrame()
+{
+    ImGuiNewFrame(GetFrameTime());
+}
+
+void ImGui_ImplRaylib_RenderDrawData(ImDrawData* draw_data)
+{
+	rlDrawRenderBatchActive();
+	rlDisableBackfaceCulling();
+
+	for (int l = 0; l < draw_data->CmdListsCount; ++l)
+	{
+		const ImDrawList* commandList = draw_data->CmdLists[l];
+
+		for (const auto& cmd : commandList->CmdBuffer)
+		{
+			EnableScissor(cmd.ClipRect.x - draw_data->DisplayPos.x, cmd.ClipRect.y - draw_data->DisplayPos.y, cmd.ClipRect.z - (cmd.ClipRect.x - draw_data->DisplayPos.x), cmd.ClipRect.w - (cmd.ClipRect.y - draw_data->DisplayPos.y));
+			if (cmd.UserCallback != nullptr)
+			{
+				cmd.UserCallback(commandList, &cmd);
+
+				continue;
+			}
+
+			ImGuiRenderTriangles(cmd.ElemCount, cmd.IdxOffset, commandList->IdxBuffer, commandList->VtxBuffer, cmd.TextureId);
+			rlDrawRenderBatchActive();
+		}
+	}
+
+	rlSetTexture(0);
+	rlDisableScissorTest();
+	rlEnableBackfaceCulling();
+}
+
+bool ImGui_ImplRaylib_ProcessEvents()
+{
+	ImGuiIO& io = ImGui::GetIO();
+
+	bool focused = IsWindowFocused();
+	if (focused != LastFrameFocused)
+		io.AddFocusEvent(focused);
+	LastFrameFocused = focused;
+
+	// handle the modifyer key events so that shortcuts work
+	bool ctrlDown = rlImGuiIsControlDown();
+	if (ctrlDown != LastControlPressed)
+		io.AddKeyEvent(ImGuiMod_Ctrl, ctrlDown);
+	LastControlPressed = ctrlDown;
+
+	bool shiftDown = rlImGuiIsShiftDown();
+	if (shiftDown != LastShiftPressed)
+		io.AddKeyEvent(ImGuiMod_Shift, shiftDown);
+	LastShiftPressed = shiftDown;
+
+	bool altDown = rlImGuiIsAltDown();
+	if (altDown != LastAltPressed)
+		io.AddKeyEvent(ImGuiMod_Alt, altDown);
+	LastAltPressed = altDown;
+
+	bool superDown = rlImGuiIsSuperDown();
+	if (superDown != LastSuperPressed)
+		io.AddKeyEvent(ImGuiMod_Super, superDown);
+	LastSuperPressed = superDown;
+
+	// get the pressed keys, they are in event order
+	int keyId = GetKeyPressed();
+	while (keyId != 0)
+	{
+		auto keyItr = RaylibKeyMap.find(KeyboardKey(keyId));
+		if (keyItr != RaylibKeyMap.end())
+			io.AddKeyEvent(keyItr->second, true);
+		keyId = GetKeyPressed();
+	}
+
+	// look for any keys that were down last frame and see if they were down and are released
+	for (const auto keyItr : RaylibKeyMap)
+	{
+		if (IsKeyReleased(keyItr.first))
+			io.AddKeyEvent(keyItr.second, false);
+	}
+
+	// add the text input in order
+	unsigned int pressed = GetCharPressed();
+	while (pressed != 0)
+	{
+		io.AddInputCharacter(pressed);
+		pressed = GetCharPressed();
+	}
+
+    return true;
+}

+ 13 - 3
rlImGui.h

@@ -6,7 +6,7 @@
 *
 *   LICENSE: ZLIB
 *
-*   Copyright (c) 2020 Jeffery Myers
+*   Copyright (c) 2023 Jeffery Myers
 *
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
@@ -41,26 +41,32 @@
 extern "C" {
 #endif
 
-// Basic API
+// High level API. This API is designed in the style of raylib and meant to work with reaylib code.
+// It will manage it's own ImGui context and call common ImGui functions (like NewFrame and Render) for you
+// for a lower level API that matches the other ImGui platforms, please see imgui_impl_raylib.h
 
 /// <summary>
 /// Sets up ImGui, loads fonts and themes
+/// Calls ImGui_ImplRaylib_Init and sets the theme. Will install Font awesome by default
 /// </summary>
 /// <param name="darkTheme">when true(default) the dark theme is used, when false the light theme is used</param>
 void rlImGuiSetup(bool darkTheme);
 
 /// <summary>
 /// Starts a new ImGui Frame
+/// Calls ImGui_ImplRaylib_NewFrame, ImGui_ImplRaylib_ProcessEvents, and ImGui::NewFrame together
 /// </summary>
 void rlImGuiBegin();
 
 /// <summary>
 /// Ends an ImGui frame and submits all ImGui drawing to raylib for processing.
+/// Calls ImGui:Render, an d ImGui_ImplRaylib_RenderDrawData to draw to the current raylib render target
 /// </summary>
 void rlImGuiEnd();
 
 /// <summary>
 /// Cleanup ImGui and unload font atlas
+/// Calls ImGui_ImplRaylib_Shutdown
 /// </summary>
 void rlImGuiShutdown();
 
@@ -69,12 +75,14 @@ void rlImGuiShutdown();
 /// <summary>
 /// Custom initialization. Not needed if you call rlImGuiSetup. Only needed if you want to add custom setup code.
 /// must be followed by rlImGuiEndInitImGui
+/// Called by ImGui_ImplRaylib_Init, and does the first part of setup, before fonts are rendered
 /// </summary>
 void rlImGuiBeginInitImGui();
 
 /// <summary>
 /// End Custom initialization. Not needed if you call rlImGuiSetup. Only needed if you want to add custom setup code.
 /// must be proceeded by rlImGuiBeginInitImGui
+/// Called by ImGui_ImplRaylib_Init and does the second part of setup, and renders fonts.
 /// </summary>
 void rlImGuiEndInitImGui();
 
@@ -91,7 +99,9 @@ void rlImGuiReloadFonts();
 /// <param name="dt">delta time, any value < 0 will use raylib GetFrameTime</param>
 void rlImGuiBeginDelta(float deltaTime);
 
-// image API
+// ImGui Image API extensions
+// Purely for convenience in working with raylib textures as images.
+// If you want to call ImGui image functions directly, simply pass them the pointer to the texture.
 
 /// <summary>
 /// Draw a texture as an image in an ImGui Context