found issue with infloops (maybe)

This commit is contained in:
Inventor Xtreme 2025-11-06 03:02:20 -05:00
parent 4f206dfa99
commit 67b9b93e11
13 changed files with 557 additions and 269 deletions

View file

@ -427,6 +427,7 @@ int main(int argc, char *argv[]) {
// peak.Draw(); // peak.Draw();
// } // }
peak.Draw(BLUE); peak.Draw(BLUE);
user.cam.EndMode(); user.cam.EndMode();
@ -446,6 +447,8 @@ int main(int argc, char *argv[]) {
} }
ImGui::End();
} else {
ImGui::End(); ImGui::End();
} }
} }

View file

@ -444,6 +444,7 @@ rl::Vector3 EPA(Simplex S, const Collider& a, const Collider& b) {
// std::cout << "BEGIN" << std::endl; // std::cout << "BEGIN" << std::endl;
size_t count = 0;
while (true) { while (true) {
// Find closest face // Find closest face
float dist = FLT_MAX; float dist = FLT_MAX;
@ -465,6 +466,11 @@ rl::Vector3 EPA(Simplex S, const Collider& a, const Collider& b) {
// std::cout << "dist to farthest hull" << supportPoint.Dotproduct(normal) - dist << std::endl; // std::cout << "dist to farthest hull" << supportPoint.Dotproduct(normal) - dist << std::endl;
if (abs(supportPoint.DotProduct(normal) - dist) < if (abs(supportPoint.DotProduct(normal) - dist) <
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !! !! !!
// dist somehow becomes max float while abs is zero.
// this is what causes inf loops
0.1) { // if distance between face and point on face is same 0.1) { // if distance between face and point on face is same
// return supportPoint.Project(normal); // return supportPoint.Project(normal);
// DrawTriangle3D(nearest.a, nearest.b, nearest.c, GREEN); // DrawTriangle3D(nearest.a, nearest.b, nearest.c, GREEN);
@ -475,5 +481,10 @@ rl::Vector3 EPA(Simplex S, const Collider& a, const Collider& b) {
// std::cout << "extending" << std::endl; // std::cout << "extending" << std::endl;
p.Extend(supportPoint); p.Extend(supportPoint);
} }
count++;
if(count > 100) {
std::cout << "greater than 100 its, exiting" << std::endl;
std::cout << "support dot normal: " << supportPoint.DotProduct(normal) << " Dist: " << dist << std::endl;
}
} }
} }

View file

@ -55,9 +55,6 @@ struct ColRay : Collider {
rl::Vector3 GetVelocity() const; rl::Vector3 GetVelocity() const;
void SetVelocity(rl::Vector3 in); void SetVelocity(rl::Vector3 in);
}; };
struct RecPrism : Collider { struct RecPrism : Collider {

View file

@ -4,10 +4,15 @@ A Raylib integration with DearImGui
rlImgui provides a backend for [Dear ImGui](https://github.com/ocornut/imgui) using [Raylib](https://www.raylib.com/). rlImgui provides a backend for [Dear ImGui](https://github.com/ocornut/imgui) using [Raylib](https://www.raylib.com/).
# Building # ImGui Version
rlImGui is setup to use premake to generate a static library and examples for Visual Studio 2019. Premake can also be used to generate makefiles for linux. rlImGui can be used as a static library, or by direclty including the files into your game project. This version was built against ImGui 1.92.1 and uses the new Font API. It is incompatbile with older versions of Dear ImGui.
If you wish to use premake, you will need to download the Premake5 executable for your platform from. https://premake.github.io/download # Building
The rlImGui repository itself is set up to use Premake to generate a static library and examples for Visual Studio 2019. Premake can also be used to generate makefiles for Linux. rlImGui can be used as a static library, or by directly including the files into your game project.
Premake is not required to use rlImGui, it is simply just what is used for development.
## Other Systems
rlImGui has no dependencies other than raylib and imgui. If you want to use any other build system, you can simply just build rlImGui and ImGui into a library, or even add the files direclty to your game if it can use C++ code. There are no specific build requirements for rlImgui itself.
# Setup # Setup
@ -64,7 +69,7 @@ void rlImGuiImageRenderTexture(const RenderTexture* image);
void rlImGuiImageRenderTextureFit(const RenderTexture* image, bool center); void rlImGuiImageRenderTextureFit(const RenderTexture* image, bool center);
bool rlImGuiImageButton(const Texture *image); bool rlImGuiImageButton(const Texture *image);
bool rlImGuiImageButtonSize(const char* name, const Texture* image, struct ImVec2 size); bool rlImGuiImageButtonSize(const char* name, const Texture* image, Vector2 size);
``` ```
# C vs C++ # C vs C++
@ -73,3 +78,13 @@ The rlImGui.h API only uses features that are common to C and C++, so rlImGui ca
# Low level API # 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 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
# Note for High DPI displays
If your system does a display scale, like 125% or %150, you will write code to handle that.
If you set the FLAG_WINDOW_HIGHDPI flag in raylib, that will create a frame buffer that is automatically scaled to fit your display. This makes it easy to define all your code in a 'normal' resolution, but has the disadvantage of making it harder to define other bufers in the native resolution. The most common side effect of this is that fonts look blury, because they are rendered at the non scaled resolution.
rlImGui on non-apple platforms will scale the default fonts by the display scale to compensate, but if you have your own fonts, you will need to do the same.
Note that apple platforms have several driver bugs with high DPI (retena displays), and rlImGui tries to compensate for them, but your results may vary or be inconsistent with other platforms.
The better option is to not use FLAG_WINDOW_HIGHDPI and let raylib run in the native resolution. You should then scale all your input values by GetWindowDPIScale.
Some examples show how to scale hardcoded values by the display scale to compensate and make your GUI look good in any scale.

View file

@ -12,8 +12,22 @@
#pragma once #pragma once
#include <string> #include <string>
#include "raylib.h"
namespace ImGuiUtils namespace ImGuiUtils
{ {
void TextWithEllipsis(const char* string, float maxWidth, bool useWordBoundaries = false, float aSpacing = 0); void TextWithEllipsis(const char* string, float maxWidth, bool useWordBoundaries = false, float aSpacing = 0);
// DPI scaling functions
inline float ScaleToDPIF(float value)
{
return GetWindowScaleDPI().x * value;
}
inline int ScaleToDPII(int value)
{
return int(GetWindowScaleDPI().x * value);
}
} }

View file

@ -29,8 +29,8 @@ int main(int argc, char* argv[])
{ {
// Initialization // Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
int screenWidth = 1900; int screenWidth = 1280;
int screenHeight = 900; int screenHeight = 800;
SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT); SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT);
InitWindow(screenWidth, screenHeight, "raylib-Extras [ImGui] example - Asset browser"); InitWindow(screenWidth, screenHeight, "raylib-Extras [ImGui] example - Asset browser");
@ -39,7 +39,6 @@ int main(int argc, char* argv[])
rlImGuiBeginInitImGui(); rlImGuiBeginInitImGui();
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFontConfig icons_config; ImFontConfig icons_config;
icons_config.MergeMode = true; icons_config.MergeMode = true;

View file

@ -16,6 +16,16 @@
#include "imgui.h" #include "imgui.h"
#include "rlImGui.h" #include "rlImGui.h"
// DPI scaling functions
float ScaleToDPIF(float value)
{
return GetWindowScaleDPI().x * value;
}
int ScaleToDPII(int value)
{
return int(GetWindowScaleDPI().x * value);
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
@ -24,7 +34,9 @@ int main(int argc, char* argv[])
int screenWidth = 1280; int screenWidth = 1280;
int screenHeight = 800; int screenHeight = 800;
SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI); // do not set the FLAG_WINDOW_HIGHDPI flag, that scales a low res framebuffer up to the native resolution.
// use the native resolution and scale your geometry.
SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE);
InitWindow(screenWidth, screenHeight, "raylib-Extras [ImGui] example - Docking"); InitWindow(screenWidth, screenHeight, "raylib-Extras [ImGui] example - Docking");
SetTargetFPS(144); SetTargetFPS(144);
rlImGuiSetup(true); rlImGuiSetup(true);

View file

@ -21,6 +21,17 @@ bool Quit = false;
bool ImGuiDemoOpen = false; bool ImGuiDemoOpen = false;
// DPI scaling functions
float ScaleToDPIF(float value)
{
return GetWindowScaleDPI().x * value;
}
int ScaleToDPII(int value)
{
return int(GetWindowScaleDPI().x * value);
}
class DocumentWindow class DocumentWindow
{ {
public: public:
@ -60,7 +71,7 @@ public:
void Show() override void Show() override
{ {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::SetNextWindowSizeConstraints(ImVec2(400, 400), ImVec2((float)GetScreenWidth(), (float)GetScreenHeight())); ImGui::SetNextWindowSizeConstraints(ImVec2(ScaleToDPIF(400.0f), ScaleToDPIF(400.0f)), ImVec2(float(GetScreenWidth()), float(GetScreenHeight())));
Focused = false; Focused = false;
@ -114,7 +125,7 @@ public:
ImGui::EndChild(); ImGui::EndChild();
} }
rlImGuiImageRect(&ViewTexture.texture, (int)size.x, (int)size.y, viewRect); rlImGuiImageRect(&ViewTexture.texture, int(size.x), int(size.y), viewRect);
} }
ImGui::End(); ImGui::End();
ImGui::PopStyleVar(); ImGui::PopStyleVar();
@ -229,7 +240,7 @@ public:
Camera.position.y = 3; Camera.position.y = 3;
Camera.position.z = -25; Camera.position.z = -25;
Image img = GenImageChecked(256, 256, 32, 32, DARKGRAY, WHITE); Image img = GenImageChecked(ScaleToDPII(256), ScaleToDPII(256), ScaleToDPII(32), ScaleToDPII(32), DARKGRAY, WHITE);
GridTexture = LoadTextureFromImage(img); GridTexture = LoadTextureFromImage(img);
UnloadImage(img); UnloadImage(img);
GenTextureMipmaps(&GridTexture); GenTextureMipmaps(&GridTexture);
@ -246,7 +257,7 @@ public:
void Show() override void Show() override
{ {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::SetNextWindowSizeConstraints(ImVec2(400, 400), ImVec2((float)GetScreenWidth(), (float)GetScreenHeight())); ImGui::SetNextWindowSizeConstraints(ImVec2(ScaleToDPIF(400.0f), ScaleToDPIF(400.0f)), ImVec2((float)GetScreenWidth(), (float)GetScreenHeight()));
if (ImGui::Begin("3D View", &Open, ImGuiWindowFlags_NoScrollbar)) if (ImGui::Begin("3D View", &Open, ImGuiWindowFlags_NoScrollbar))
{ {
@ -272,7 +283,7 @@ public:
float period = 10; float period = 10;
float magnitude = 25; float magnitude = 25;
Camera.position.x = (float)(sinf((float)GetTime() / period) * magnitude); Camera.position.x = sinf(float(GetTime() / period)) * magnitude;
BeginTextureMode(ViewTexture); BeginTextureMode(ViewTexture);
ClearBackground(SKYBLUE); ClearBackground(SKYBLUE);
@ -340,8 +351,10 @@ int main(int argc, char* argv[])
int screenWidth = 1900; int screenWidth = 1900;
int screenHeight = 900; int screenHeight = 900;
// do not set the FLAG_WINDOW_HIGHDPI flag, that scales a low res framebuffer up to the native resolution.
// use the native resolution and scale your geometry.
SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT); SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT);
InitWindow(screenWidth, screenHeight, "raylib-Extras [ImGui] example - ImGui Demo"); InitWindow(screenWidth, screenHeight, "raylib-Extras [ImGui] example - Editor Example");
SetTargetFPS(144); SetTargetFPS(144);
rlImGuiSetup(true); rlImGuiSetup(true);
ImGui::GetIO().ConfigWindowsMoveFromTitleBarOnly = true; ImGui::GetIO().ConfigWindowsMoveFromTitleBarOnly = true;

View file

@ -11,11 +11,28 @@
#include "imgui_impl_raylib.h" #include "imgui_impl_raylib.h"
#include "raylib.h" #include "raylib.h"
#include <cstdint>
// DPI scaling functions
// Use these to scale any hardcoded values to the native display resolution
float ScaleToDPIF(float value)
{
return GetWindowScaleDPI().x * value;
}
int ScaleToDPII(int value)
{
return int(GetWindowScaleDPI().x * value);
}
// Main code // Main code
int main(int, char**) int main(int, char**)
{ {
// Setup raylib window // Setup raylib window
SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI); // do not set the FLAG_WINDOW_HIGHDPI flag, that scales a low res framebuffer up to the native resolution.
// use the native resolution and scale your geometry.
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(1280, 720, "Dear ImGui Raylib(OpenGL) example"); InitWindow(1280, 720, "Dear ImGui Raylib(OpenGL) example");
// Setup Dear ImGui context // Setup Dear ImGui context
@ -24,6 +41,13 @@ int main(int, char**)
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// tell ImGui the display scale
if (!IsWindowState(FLAG_WINDOW_HIGHDPI))
{
io.DisplayFramebufferScale.x = GetWindowScaleDPI().x;
io.DisplayFramebufferScale.y = GetWindowScaleDPI().y;
}
// Setup Dear ImGui style // Setup Dear ImGui style
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
//ImGui::StyleColorsLight(); //ImGui::StyleColorsLight();
@ -39,16 +63,27 @@ int main(int, char**)
// - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - 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. // - 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 \\ ! // - 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();
// to properly scale for high DPI displays, we need to cale the font size by the dpi sale
static constexpr int DefaultFonSize = 13;
ImFontConfig defaultConfig;
defaultConfig.SizePixels = DefaultFonSize;
if (!IsWindowState(FLAG_WINDOW_HIGHDPI))
{
defaultConfig.SizePixels = defaultConfig.SizePixels * GetWindowScaleDPI().y;
defaultConfig.RasterizerMultiply = GetWindowScaleDPI().y;
}
defaultConfig.PixelSnapH = true;
io.Fonts->AddFontDefault(&defaultConfig);
//io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.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/Roboto-Medium.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
ImFont* font = io.Fonts->AddFontFromFileTTF("resources/driusstraight.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); // ImFont* font = io.Fonts->AddFontFromFileTTF("resources/driusstraight.ttf", ScaleToDPIF(18.0f), nullptr, io.Fonts->GetGlyphRangesJapanese());
IM_ASSERT(font != nullptr); // IM_ASSERT(font != nullptr);
// required to be called to cache the font texture with raylib
ImGui_ImplRaylib_BuildFontAtlas();
// Our state // Our state
bool show_demo_window = true; bool show_demo_window = true;
@ -86,7 +121,7 @@ int main(int, char**)
ImGui::Checkbox("Another Window", &show_another_window); 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::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 ImGui::ColorEdit3("clear color", &clear_color.x); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
counter++; counter++;
@ -107,11 +142,10 @@ int main(int, char**)
ImGui::End(); ImGui::End();
} }
// Rendering // Rendering
ImGui::Render(); ImGui::Render();
BeginDrawing(); 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) }); ClearBackground(Color{ uint8_t(clear_color.x * 255), uint8_t(clear_color.y * 255), uint8_t(clear_color.z * 255), uint8_t(clear_color.w * 255) });
ImGui_ImplRaylib_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplRaylib_RenderDrawData(ImGui::GetDrawData());
EndDrawing(); EndDrawing();

View file

@ -17,6 +17,18 @@
#include "imgui.h" #include "imgui.h"
#include "rlImGui.h" #include "rlImGui.h"
// DPI scaling functions
float ScaleToDPIF(float value)
{
return GetWindowScaleDPI().x * value;
}
int ScaleToDPII(int value)
{
return int(GetWindowScaleDPI().x * value);
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
// Initialization // Initialization
@ -29,6 +41,8 @@ int main(int argc, char* argv[])
SetTargetFPS(144); SetTargetFPS(144);
rlImGuiSetup(true); rlImGuiSetup(true);
Texture image = LoadTexture("resources/parrots.png");
// Main game loop // Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key while (!WindowShouldClose()) // Detect window close button or ESC key
{ {
@ -42,16 +56,26 @@ int main(int argc, char* argv[])
bool open = true; bool open = true;
ImGui::ShowDemoWindow(&open); ImGui::ShowDemoWindow(&open);
open = true;
if (ImGui::Begin("Test Window", &open))
{
ImGui::TextUnformatted(ICON_FA_JEDI);
rlImGuiImage(&image);
}
ImGui::End();
// end ImGui Content // end ImGui Content
rlImGuiEnd(); rlImGuiEnd();
EndDrawing(); EndDrawing();
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
} }
rlImGuiShutdown();
// De-Initialization // De-Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
rlImGuiShutdown();
UnloadTexture(image);
CloseWindow(); // Close window and OpenGL context CloseWindow(); // Close window and OpenGL context
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------

View file

@ -45,7 +45,6 @@
#ifndef IMGUI_DISABLE #ifndef IMGUI_DISABLE
IMGUI_IMPL_API bool ImGui_ImplRaylib_Init(void); IMGUI_IMPL_API bool ImGui_ImplRaylib_Init(void);
IMGUI_IMPL_API void ImGui_ImplRaylib_BuildFontAtlas(void);
IMGUI_IMPL_API void ImGui_ImplRaylib_Shutdown(void); IMGUI_IMPL_API void ImGui_ImplRaylib_Shutdown(void);
IMGUI_IMPL_API void ImGui_ImplRaylib_NewFrame(void); IMGUI_IMPL_API void ImGui_ImplRaylib_NewFrame(void);
IMGUI_IMPL_API void ImGui_ImplRaylib_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API void ImGui_ImplRaylib_RenderDrawData(ImDrawData* draw_data);

View file

@ -1,32 +1,32 @@
/********************************************************************************************** /**********************************************************************************************
* *
* raylibExtras * Utilities and Shared Components for Raylib * raylibExtras * Utilities and Shared Components for Raylib
* *
* rlImGui * basic ImGui integration * rlImGui * basic ImGui integration
* *
* LICENSE: ZLIB * LICENSE: ZLIB
* *
* Copyright (c) 2024 Jeffery Myers * Copyright (c) 2024 Jeffery Myers
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software. * copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * 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 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
* *
**********************************************************************************************/ **********************************************************************************************/
#include "rlImGui.h" #include "rlImGui.h"
#include "imgui_impl_raylib.h" #include "imgui_impl_raylib.h"
@ -36,10 +36,10 @@
#include "imgui.h" #include "imgui.h"
#include <cstdint>
#include <limits>
#include <map>
#include <math.h> #include <math.h>
#include <map>
#include <limits>
#include <cstdint>
#ifndef NO_FONT_AWESOME #ifndef NO_FONT_AWESOME
#include "extras/FA6FreeSolidFontData.h" #include "extras/FA6FreeSolidFontData.h"
@ -48,7 +48,7 @@
static ImGuiMouseCursor CurrentMouseCursor = ImGuiMouseCursor_COUNT; static ImGuiMouseCursor CurrentMouseCursor = ImGuiMouseCursor_COUNT;
static MouseCursor MouseCursorMap[ImGuiMouseCursor_COUNT]; static MouseCursor MouseCursorMap[ImGuiMouseCursor_COUNT];
ImGuiContext *GlobalContext = nullptr; ImGuiContext* GlobalContext = nullptr;
static std::map<KeyboardKey, ImGuiKey> RaylibKeyMap; static std::map<KeyboardKey, ImGuiKey> RaylibKeyMap;
@ -60,68 +60,86 @@ static bool LastAltPressed = false;
static bool LastSuperPressed = false; static bool LastSuperPressed = false;
// internal only functions // internal only functions
bool rlImGuiIsControlDown() { bool rlImGuiIsControlDown() { return IsKeyDown(KEY_RIGHT_CONTROL) || IsKeyDown(KEY_LEFT_CONTROL); }
return IsKeyDown(KEY_RIGHT_CONTROL) || IsKeyDown(KEY_LEFT_CONTROL); bool rlImGuiIsShiftDown() { return IsKeyDown(KEY_RIGHT_SHIFT) || IsKeyDown(KEY_LEFT_SHIFT); }
} bool rlImGuiIsAltDown() { return IsKeyDown(KEY_RIGHT_ALT) || IsKeyDown(KEY_LEFT_ALT); }
bool rlImGuiIsShiftDown() { bool rlImGuiIsSuperDown() { return IsKeyDown(KEY_RIGHT_SUPER) || IsKeyDown(KEY_LEFT_SUPER); }
return IsKeyDown(KEY_RIGHT_SHIFT) || IsKeyDown(KEY_LEFT_SHIFT);
} struct ImGui_ImplRaylib_Data
bool rlImGuiIsAltDown() { {
return IsKeyDown(KEY_RIGHT_ALT) || IsKeyDown(KEY_LEFT_ALT); };
}
bool rlImGuiIsSuperDown() { ImGui_ImplRaylib_Data* ImGui_ImplRaylib_GetBackendData()
return IsKeyDown(KEY_RIGHT_SUPER) || IsKeyDown(KEY_LEFT_SUPER); {
return ImGui::GetCurrentContext() ? static_cast<ImGui_ImplRaylib_Data*>(ImGui::GetPlatformIO().Renderer_RenderState) : nullptr;
} }
void ReloadFonts(void) { void ImGui_ImplRaylib_CreateBackendData()
ImGuiIO &io = ImGui::GetIO(); {
unsigned char *pixels = nullptr; if (!ImGui::GetCurrentContext() || ImGui::GetPlatformIO().Renderer_RenderState)
return;
int width; ImGui::GetPlatformIO().Renderer_RenderState = MemAlloc(sizeof(ImGui_ImplRaylib_Data));
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 = (ImTextureID)fontTexture;
} }
static const char *GetClipTextCallback(ImGuiContext *) { void ImGui_ImplRaylib_FreeBackendData()
{
if (!ImGui::GetCurrentContext())
return;
MemFree(ImGui::GetPlatformIO().Renderer_RenderState);
}
Vector2 GetDisplayScale()
{
#if defined(__EMSCRIPTEN__)
return Vector2{ 1,1 };
#else
return GetWindowScaleDPI();
#endif
}
static const char* GetClipTextCallback(ImGuiContext*)
{
return GetClipboardText(); return GetClipboardText();
} }
static void SetClipTextCallback(ImGuiContext *, const char *text) { static void SetClipTextCallback(ImGuiContext*, const char* text)
{
SetClipboardText(text); SetClipboardText(text);
} }
static void ImGuiNewFrame(float deltaTime) { static void ImGuiNewFrame(float deltaTime)
ImGuiIO &io = ImGui::GetIO(); {
ImGuiIO& io = ImGui::GetIO();
auto* platData = ImGui_ImplRaylib_GetBackendData();
if (!platData)
{
ImGui_ImplRaylib_CreateBackendData();
platData = ImGui_ImplRaylib_GetBackendData();
if (!platData)
return;
}
// Vector2 resolutionScale = GetWindowScaleDPI(); Vector2 resolutionScale = GetDisplayScale();
Vector2 resolutionScale = Vector2{1, 1};
#ifndef PLATFORM_DRM #ifndef PLATFORM_DRM
if (IsWindowFullscreen()) { if (IsWindowFullscreen())
{
int monitor = GetCurrentMonitor(); int monitor = GetCurrentMonitor();
io.DisplaySize.x = float(GetMonitorWidth(monitor)); io.DisplaySize.x = float(GetMonitorWidth(monitor));
io.DisplaySize.y = float(GetMonitorHeight(monitor)); io.DisplaySize.y = float(GetMonitorHeight(monitor));
} else { }
else
{
io.DisplaySize.x = float(GetScreenWidth()); io.DisplaySize.x = float(GetScreenWidth());
io.DisplaySize.y = float(GetScreenHeight()); io.DisplaySize.y = float(GetScreenHeight());
} }
#if !defined(__APPLE__) #if !defined(__APPLE__)
if (!IsWindowState(FLAG_WINDOW_HIGHDPI)) if (!IsWindowState(FLAG_WINDOW_HIGHDPI))
resolutionScale = Vector2{1, 1}; resolutionScale = Vector2{ 1,1 };
#endif #endif
#else #else
io.DisplaySize.x = float(GetScreenWidth()); io.DisplaySize.x = float(GetScreenWidth());
@ -135,20 +153,25 @@ static void ImGuiNewFrame(float deltaTime) {
io.DeltaTime = deltaTime; io.DeltaTime = deltaTime;
if (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_HasMouseCursors) { if (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_HasMouseCursors)
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) == 0) { {
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) == 0)
{
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (imgui_cursor != CurrentMouseCursor || io.MouseDrawCursor) { if (imgui_cursor != CurrentMouseCursor || io.MouseDrawCursor)
{
CurrentMouseCursor = imgui_cursor; CurrentMouseCursor = imgui_cursor;
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None) { if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
{
HideCursor(); HideCursor();
} else { }
else
{
ShowCursor(); ShowCursor();
if (!(io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)) { if (!(io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange))
SetMouseCursor((imgui_cursor > -1 && imgui_cursor < ImGuiMouseCursor_COUNT) {
? MouseCursorMap[imgui_cursor] SetMouseCursor((imgui_cursor > -1 && imgui_cursor < ImGuiMouseCursor_COUNT) ? MouseCursorMap[imgui_cursor] : MOUSE_CURSOR_DEFAULT);
: MOUSE_CURSOR_DEFAULT);
} }
} }
} }
@ -156,28 +179,40 @@ static void ImGuiNewFrame(float deltaTime) {
} }
} }
static void ImGuiTriangleVert(ImDrawVert &idx_vert) { static void ImGuiTriangleVert(const ImDrawVert& idx_vert)
Color *c; {
c = (Color *)&idx_vert.col; #ifdef __cpp_designated_initializers
rlColor4ub(c->r, c->g, c->b, c->a); Color c {
.r = static_cast<unsigned char>(idx_vert.col>>0),
.g = static_cast<unsigned char>(idx_vert.col>>8),
.b = static_cast<unsigned char>(idx_vert.col>>16),
.a = static_cast<unsigned char>(idx_vert.col>>24),
};
#else
Color c {
static_cast<unsigned char>(idx_vert.col>>0),
static_cast<unsigned char>(idx_vert.col>>8),
static_cast<unsigned char>(idx_vert.col>>16),
static_cast<unsigned char>(idx_vert.col>>24),
};
#endif
rlColor4ub(c.r, c.g, c.b, c.a);
rlTexCoord2f(idx_vert.uv.x, idx_vert.uv.y); rlTexCoord2f(idx_vert.uv.x, idx_vert.uv.y);
rlVertex2f(idx_vert.pos.x, idx_vert.pos.y); rlVertex2f(idx_vert.pos.x, idx_vert.pos.y);
} }
static void ImGuiRenderTriangles(unsigned int count, int indexStart, static void ImGuiRenderTriangles(unsigned int count, int indexStart, const ImVector<ImDrawIdx>& indexBuffer, const ImVector<ImDrawVert>& vertBuffer, ImTextureID texturePtr)
const ImVector<ImDrawIdx> &indexBuffer, {
const ImVector<ImDrawVert> &vertBuffer, void *texturePtr) {
if (count < 3) if (count < 3)
return; return;
Texture *texture = (Texture *)texturePtr; unsigned int textureId = static_cast<unsigned int>(texturePtr);
unsigned int textureId = (texture == nullptr) ? 0 : texture->id;
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
rlSetTexture(textureId); rlSetTexture(textureId);
for (unsigned int i = 0; i <= (count - 3); i += 3) { for (unsigned int i = 0; i <= (count - 3); i += 3)
{
ImDrawIdx indexA = indexBuffer[indexStart + i]; ImDrawIdx indexA = indexBuffer[indexStart + i];
ImDrawIdx indexB = indexBuffer[indexStart + i + 1]; ImDrawIdx indexB = indexBuffer[indexStart + i + 1];
ImDrawIdx indexC = indexBuffer[indexStart + i + 2]; ImDrawIdx indexC = indexBuffer[indexStart + i + 2];
@ -193,23 +228,28 @@ static void ImGuiRenderTriangles(unsigned int count, int indexStart,
rlEnd(); rlEnd();
} }
static void EnableScissor(float x, float y, float width, float height) { static void EnableScissor(float x, float y, float width, float height)
{
rlEnableScissorTest(); rlEnableScissorTest();
ImGuiIO &io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ImVec2 scale = io.DisplayFramebufferScale; ImVec2 scale = io.DisplayFramebufferScale;
#if !defined(__APPLE__) #if !defined(__APPLE__)
if (!IsWindowState(FLAG_WINDOW_HIGHDPI)) { if (!IsWindowState(FLAG_WINDOW_HIGHDPI))
{
scale.x = 1; scale.x = 1;
scale.y = 1; scale.y = 1;
} }
#endif #endif
rlScissor((int)(x * scale.x), int((io.DisplaySize.y - (int)(y + height)) * scale.y), rlScissor((int)(x * scale.x),
(int)(width * scale.x), (int)(height * scale.y)); int((io.DisplaySize.y - (int)(y + height)) * scale.y),
(int)(width * scale.x),
(int)(height * scale.y));
} }
static void SetupMouseCursors(void) { static void SetupMouseCursors(void)
{
MouseCursorMap[ImGuiMouseCursor_Arrow] = MOUSE_CURSOR_ARROW; MouseCursorMap[ImGuiMouseCursor_Arrow] = MOUSE_CURSOR_ARROW;
MouseCursorMap[ImGuiMouseCursor_TextInput] = MOUSE_CURSOR_IBEAM; MouseCursorMap[ImGuiMouseCursor_TextInput] = MOUSE_CURSOR_IBEAM;
MouseCursorMap[ImGuiMouseCursor_Hand] = MOUSE_CURSOR_POINTING_HAND; MouseCursorMap[ImGuiMouseCursor_Hand] = MOUSE_CURSOR_POINTING_HAND;
@ -221,9 +261,10 @@ static void SetupMouseCursors(void) {
MouseCursorMap[ImGuiMouseCursor_NotAllowed] = MOUSE_CURSOR_NOT_ALLOWED; MouseCursorMap[ImGuiMouseCursor_NotAllowed] = MOUSE_CURSOR_NOT_ALLOWED;
} }
void SetupFontAwesome(void) { void SetupFontAwesome(void)
{
#ifndef NO_FONT_AWESOME #ifndef NO_FONT_AWESOME
static const ImWchar icons_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0}; static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFontConfig icons_config; ImFontConfig icons_config;
icons_config.MergeMode = true; icons_config.MergeMode = true;
icons_config.PixelSnapH = true; icons_config.PixelSnapH = true;
@ -236,18 +277,26 @@ void SetupFontAwesome(void) {
icons_config.GlyphRanges = icons_ranges; icons_config.GlyphRanges = icons_ranges;
ImGuiIO &io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontFromMemoryCompressedTTF((void *)fa_solid_900_compressed_data, float size = FONT_AWESOME_ICON_SIZE;
fa_solid_900_compressed_size, FONT_AWESOME_ICON_SIZE, #if !defined(__APPLE__)
&icons_config, icons_ranges); if (!IsWindowState(FLAG_WINDOW_HIGHDPI))
size *= GetDisplayScale().y;
icons_config.RasterizerMultiply = GetDisplayScale().y;
#endif #endif
io.Fonts->AddFontFromMemoryCompressedTTF((void*)fa_solid_900_compressed_data, fa_solid_900_compressed_size, size, &icons_config, icons_ranges);
#endif
} }
void SetupBackend(void) { void SetupBackend(void)
ImGuiIO &io = ImGui::GetIO(); {
ImGuiIO& io = ImGui::GetIO();
io.BackendPlatformName = "imgui_impl_raylib"; io.BackendPlatformName = "imgui_impl_raylib";
io.BackendFlags |= ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_HasSetMousePos; io.BackendFlags |= ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_RendererHasTextures;
#ifndef PLATFORM_DRM #ifndef PLATFORM_DRM
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
@ -255,15 +304,18 @@ void SetupBackend(void) {
io.MousePos = ImVec2(0, 0); io.MousePos = ImVec2(0, 0);
ImGuiPlatformIO &platformIO = ImGui::GetPlatformIO(); ImGuiPlatformIO& platformIO = ImGui::GetPlatformIO();
platformIO.Platform_SetClipboardTextFn = SetClipTextCallback; platformIO.Platform_SetClipboardTextFn = SetClipTextCallback;
platformIO.Platform_GetClipboardTextFn = GetClipTextCallback; platformIO.Platform_GetClipboardTextFn = GetClipTextCallback;
platformIO.Platform_ClipboardUserData = nullptr; platformIO.Platform_ClipboardUserData = nullptr;
ImGui_ImplRaylib_CreateBackendData();
} }
void rlImGuiEndInitImGui(void) { void rlImGuiEndInitImGui(void)
{
ImGui::SetCurrentContext(GlobalContext); ImGui::SetCurrentContext(GlobalContext);
SetupFontAwesome(); SetupFontAwesome();
@ -271,11 +323,10 @@ void rlImGuiEndInitImGui(void) {
SetupMouseCursors(); SetupMouseCursors();
SetupBackend(); SetupBackend();
ReloadFonts();
} }
static void SetupKeymap(void) { static void SetupKeymap(void)
{
if (!RaylibKeyMap.empty()) if (!RaylibKeyMap.empty())
return; return;
@ -387,7 +438,8 @@ static void SetupKeymap(void) {
RaylibKeyMap[KEY_KP_EQUAL] = ImGuiKey_KeypadEqual; RaylibKeyMap[KEY_KP_EQUAL] = ImGuiKey_KeypadEqual;
} }
static void SetupGlobals(void) { static void SetupGlobals(void)
{
LastFrameFocused = IsWindowFocused(); LastFrameFocused = IsWindowFocused();
LastControlPressed = false; LastControlPressed = false;
LastShiftPressed = false; LastShiftPressed = false;
@ -395,17 +447,33 @@ static void SetupGlobals(void) {
LastSuperPressed = false; LastSuperPressed = false;
} }
void rlImGuiBeginInitImGui(void) { void rlImGuiBeginInitImGui(void)
{
SetupGlobals(); SetupGlobals();
if (GlobalContext == nullptr) if (GlobalContext == nullptr)
GlobalContext = ImGui::CreateContext(nullptr); GlobalContext = ImGui::CreateContext(nullptr);
SetupKeymap(); SetupKeymap();
ImGuiIO &io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontDefault();
ImFontConfig defaultConfig;
static constexpr int DefaultFonSize = 13;
defaultConfig.SizePixels = DefaultFonSize;
#if !defined(__APPLE__)
if (!IsWindowState(FLAG_WINDOW_HIGHDPI))
defaultConfig.SizePixels = ceilf(defaultConfig.SizePixels * GetDisplayScale().y);
defaultConfig.RasterizerMultiply = GetDisplayScale().y;
#endif
defaultConfig.PixelSnapH = true;
io.Fonts->AddFontDefault(&defaultConfig);
} }
void rlImGuiSetup(bool dark) { void rlImGuiSetup(bool dark)
{
rlImGuiBeginInitImGui(); rlImGuiBeginInitImGui();
if (dark) if (dark)
@ -416,18 +484,14 @@ void rlImGuiSetup(bool dark) {
rlImGuiEndInitImGui(); rlImGuiEndInitImGui();
} }
void rlImGuiReloadFonts(void) { void rlImGuiBegin(void)
ImGui::SetCurrentContext(GlobalContext); {
ReloadFonts();
}
void rlImGuiBegin(void) {
ImGui::SetCurrentContext(GlobalContext); ImGui::SetCurrentContext(GlobalContext);
rlImGuiBeginDelta(GetFrameTime()); rlImGuiBeginDelta(GetFrameTime());
} }
void rlImGuiBeginDelta(float deltaTime) { void rlImGuiBeginDelta(float deltaTime)
{
ImGui::SetCurrentContext(GlobalContext); ImGui::SetCurrentContext(GlobalContext);
ImGuiNewFrame(deltaTime); ImGuiNewFrame(deltaTime);
@ -435,13 +499,15 @@ void rlImGuiBeginDelta(float deltaTime) {
ImGui::NewFrame(); ImGui::NewFrame();
} }
void rlImGuiEnd(void) { void rlImGuiEnd(void)
{
ImGui::SetCurrentContext(GlobalContext); ImGui::SetCurrentContext(GlobalContext);
ImGui::Render(); ImGui::Render();
ImGui_ImplRaylib_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplRaylib_RenderDrawData(ImGui::GetDrawData());
} }
void rlImGuiShutdown(void) { void rlImGuiShutdown(void)
{
if (GlobalContext == nullptr) if (GlobalContext == nullptr)
return; return;
@ -452,58 +518,63 @@ void rlImGuiShutdown(void) {
GlobalContext = nullptr; GlobalContext = nullptr;
} }
void rlImGuiImage(const Texture *image) { void rlImGuiImage(const Texture* image)
{
if (!image) if (!image)
return; return;
if (GlobalContext) if (GlobalContext)
ImGui::SetCurrentContext(GlobalContext); ImGui::SetCurrentContext(GlobalContext);
ImGui::Image((ImTextureID)image, ImVec2(float(image->width), float(image->height))); ImGui::Image(ImTextureID(image->id), ImVec2(float(image->width), float(image->height)));
} }
bool rlImGuiImageButton(const char *name, const Texture *image) { bool rlImGuiImageButton(const char* name, const Texture* image)
{
if (!image) if (!image)
return false; return false;
if (GlobalContext) if (GlobalContext)
ImGui::SetCurrentContext(GlobalContext); ImGui::SetCurrentContext(GlobalContext);
return ImGui::ImageButton(name, (ImTextureID)image, return ImGui::ImageButton(name, ImTextureID(image->id), ImVec2(float(image->width), float(image->height)));
ImVec2(float(image->width), float(image->height)));
} }
bool rlImGuiImageButtonSize(const char *name, const Texture *image, ImVec2 size) { bool rlImGuiImageButtonSize(const char* name, const Texture* image, Vector2 size)
{
if (!image) if (!image)
return false; return false;
if (GlobalContext) if (GlobalContext)
ImGui::SetCurrentContext(GlobalContext); ImGui::SetCurrentContext(GlobalContext);
return ImGui::ImageButton(name, (ImTextureID)image, size); return ImGui::ImageButton(name, ImTextureID(image->id), ImVec2(size.x, size.y));
} }
void rlImGuiImageSize(const Texture *image, int width, int height) { void rlImGuiImageSize(const Texture* image, int width, int height)
{
if (!image) if (!image)
return; return;
if (GlobalContext) if (GlobalContext)
ImGui::SetCurrentContext(GlobalContext); ImGui::SetCurrentContext(GlobalContext);
ImGui::Image((ImTextureID)image, ImVec2(float(width), float(height))); ImGui::Image(ImTextureID(image->id), ImVec2(float(width), float(height)));
} }
void rlImGuiImageSizeV(const Texture *image, Vector2 size) { void rlImGuiImageSizeV(const Texture* image, Vector2 size)
{
if (!image) if (!image)
return; return;
if (GlobalContext) if (GlobalContext)
ImGui::SetCurrentContext(GlobalContext); ImGui::SetCurrentContext(GlobalContext);
ImGui::Image((ImTextureID)image, ImVec2(size.x, size.y)); ImGui::Image(ImTextureID(image->id), ImVec2(size.x, size.y));
} }
void rlImGuiImageRect(const Texture *image, int destWidth, int destHeight, Rectangle sourceRect) { void rlImGuiImageRect(const Texture* image, int destWidth, int destHeight, Rectangle sourceRect)
{
if (!image) if (!image)
return; return;
@ -513,38 +584,44 @@ void rlImGuiImageRect(const Texture *image, int destWidth, int destHeight, Recta
ImVec2 uv0; ImVec2 uv0;
ImVec2 uv1; ImVec2 uv1;
if (sourceRect.width < 0) { if (sourceRect.width < 0)
uv0.x = -((float)sourceRect.x / image->width); {
uv1.x = (uv0.x - (float)(fabs(sourceRect.width) / image->width)); uv0.x = -sourceRect.x / image->width;
} else { uv1.x = (uv0.x - float(fabs(sourceRect.width) / image->width));
uv0.x = (float)sourceRect.x / image->width; }
uv1.x = uv0.x + (float)(sourceRect.width / image->width); else
{
uv0.x = sourceRect.x / image->width;
uv1.x = uv0.x + float(sourceRect.width / image->width);
} }
if (sourceRect.height < 0) { if (sourceRect.height < 0)
uv0.y = -((float)sourceRect.y / image->height); {
uv1.y = (uv0.y - (float)(fabs(sourceRect.height) / image->height)); uv0.y = -sourceRect.y / image->height;
} else { uv1.y = (uv0.y - fabsf(sourceRect.height) / image->height);
uv0.y = (float)sourceRect.y / image->height; }
uv1.y = uv0.y + (float)(sourceRect.height / image->height); else
{
uv0.y = sourceRect.y / image->height;
uv1.y = uv0.y + sourceRect.height / image->height;
} }
ImGui::Image((ImTextureID)image, ImVec2(float(destWidth), float(destHeight)), uv0, uv1); ImGui::Image((ImTextureID)image->id, ImVec2(float(destWidth), float(destHeight)), uv0, uv1);
// ImGui::Image((ImTextureID)image, ImVec2(float(destWidth), float(destHeight)));
} }
void rlImGuiImageRenderTexture(const RenderTexture *image) { void rlImGuiImageRenderTexture(const RenderTexture* image)
{
if (!image) if (!image)
return; return;
if (GlobalContext) if (GlobalContext)
ImGui::SetCurrentContext(GlobalContext); ImGui::SetCurrentContext(GlobalContext);
rlImGuiImageRect(&image->texture, image->texture.width, image->texture.height, rlImGuiImageRect(&image->texture, image->texture.width, image->texture.height, Rectangle{ 0,0, float(image->texture.width), -float(image->texture.height) });
Rectangle{0, 0, float(image->texture.width), -float(image->texture.height)});
} }
void rlImGuiImageRenderTextureFit(const RenderTexture *image, bool center) { void rlImGuiImageRenderTextureFit(const RenderTexture* image, bool center)
{
if (!image) if (!image)
return; return;
@ -556,25 +633,27 @@ void rlImGuiImageRenderTextureFit(const RenderTexture *image, bool center) {
float scale = area.x / image->texture.width; float scale = area.x / image->texture.width;
float y = image->texture.height * scale; float y = image->texture.height * scale;
if (y > area.y) { if (y > area.y)
{
scale = area.y / image->texture.height; scale = area.y / image->texture.height;
} }
int sizeX = int(image->texture.width * scale); int sizeX = int(image->texture.width * scale);
int sizeY = int(image->texture.height * scale); int sizeY = int(image->texture.height * scale);
if (center) { if (center)
{
ImGui::SetCursorPosX(0); ImGui::SetCursorPosX(0);
ImGui::SetCursorPosX(area.x / 2 - sizeX / 2); ImGui::SetCursorPosX(area.x/2 - sizeX/2);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (area.y / 2 - sizeY / 2)); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (area.y / 2 - sizeY / 2));
} }
rlImGuiImageRect(&image->texture, sizeX, sizeY, rlImGuiImageRect(&image->texture, sizeX, sizeY, Rectangle{ 0,0, float(image->texture.width), -float(image->texture.height) });
Rectangle{0, 0, float(image->texture.width), -float(image->texture.height)});
} }
// raw ImGui backend API // raw ImGui backend API
bool ImGui_ImplRaylib_Init(void) { bool ImGui_ImplRaylib_Init(void)
{
SetupGlobals(); SetupGlobals();
SetupKeymap(); SetupKeymap();
@ -586,46 +665,121 @@ bool ImGui_ImplRaylib_Init(void) {
return true; return true;
} }
void ImGui_ImplRaylib_BuildFontAtlas(void) {
ReloadFonts();
}
void ImGui_ImplRaylib_Shutdown() { void ImGui_ImplRaylib_Shutdown()
ImGuiIO &io = ImGui::GetIO(); {
Texture2D *fontTexture = (Texture2D *)io.Fonts->TexID; ImGuiIO& io =ImGui::GetIO();
if (fontTexture) { for (auto& texture : ImGui::GetPlatformIO().Textures)
UnloadTexture(*fontTexture); {
MemFree(fontTexture); if (texture->Status != ImTextureStatus_Destroyed)
{
Texture* backendData = (Texture*)texture->BackendUserData;
if (backendData && IsTextureValid(*backendData))
{
UnloadTexture(*backendData);
}
if (backendData)
MemFree(backendData);
texture->BackendUserData = nullptr;
texture->Status = ImTextureStatus_Destroyed;
texture->SetTexID(ImTextureID_Invalid);
}
} }
io.Fonts->TexID = 0; ImGui_ImplRaylib_FreeBackendData();
} }
void ImGui_ImplRaylib_NewFrame(void) { void ImGui_ImplRaylib_NewFrame(void)
{
ImGuiNewFrame(GetFrameTime()); ImGuiNewFrame(GetFrameTime());
} }
void ImGui_ImplRaylib_RenderDrawData(ImDrawData *draw_data) { void ImGui_ImplRaylib_UpdateTexture(ImTextureData* tex)
{
switch (tex->Status)
{
case ImTextureStatus_OK:
case ImTextureStatus_Destroyed:
default:
break;
case ImTextureStatus_WantCreate:
{
Image img = { 0 };
img.width = tex->Width;
img.height = tex->Height;
img.format = tex->Format == ImTextureFormat_Alpha8 ? PIXELFORMAT_UNCOMPRESSED_GRAYSCALE : PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
img.mipmaps = 1;
img.data = tex->GetPixels();
Texture* texture = (Texture*)MemAlloc(sizeof(Texture));
tex->BackendUserData = texture;;
*texture = LoadTextureFromImage(img);
tex->SetTexID(ImTextureID(texture->id));
tex->Status = ImTextureStatus_OK;
}
break;
case ImTextureStatus_WantUpdates:
{
Texture* texture = (Texture*)tex->BackendUserData;
if (!texture)
break;
UpdateTexture(*texture, tex->GetPixels());
tex->Status = ImTextureStatus_OK;
}
break;
case ImTextureStatus_WantDestroy:
{
Texture* texture = (Texture*)tex->BackendUserData;
if (!texture)
break;
UnloadTexture(*texture);
tex->Status = ImTextureStatus_Destroyed;
MemFree(texture);
tex->BackendUserData = nullptr;
tex->SetTexID(ImTextureID_Invalid);
}
break;
}
}
void ImGui_ImplRaylib_RenderDrawData(ImDrawData* draw_data)
{
if (draw_data->Textures != nullptr)
{
for (ImTextureData* tex : *draw_data->Textures)
{
if (tex->Status != ImTextureStatus_OK)
ImGui_ImplRaylib_UpdateTexture(tex);
}
}
rlDrawRenderBatchActive(); rlDrawRenderBatchActive();
rlDisableBackfaceCulling(); rlDisableBackfaceCulling();
for (int l = 0; l < draw_data->CmdListsCount; ++l) { for (int l = 0; l < draw_data->CmdListsCount; ++l)
const ImDrawList *commandList = draw_data->CmdLists[l]; {
const ImDrawList* commandList = draw_data->CmdLists[l];
for (const auto &cmd : commandList->CmdBuffer) { for (const auto& cmd : commandList->CmdBuffer)
EnableScissor(cmd.ClipRect.x - draw_data->DisplayPos.x, {
cmd.ClipRect.y - draw_data->DisplayPos.y, 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));
cmd.ClipRect.z - (cmd.ClipRect.x - draw_data->DisplayPos.x), if (cmd.UserCallback != nullptr)
cmd.ClipRect.w - (cmd.ClipRect.y - draw_data->DisplayPos.y)); {
if (cmd.UserCallback != nullptr) {
cmd.UserCallback(commandList, &cmd); cmd.UserCallback(commandList, &cmd);
continue; continue;
} }
ImGuiRenderTriangles(cmd.ElemCount, cmd.IdxOffset, commandList->IdxBuffer, ImGuiRenderTriangles(cmd.ElemCount, cmd.IdxOffset, commandList->IdxBuffer, commandList->VtxBuffer, cmd.GetTexID());
commandList->VtxBuffer, (Texture2D *)cmd.TextureId);
rlDrawRenderBatchActive(); rlDrawRenderBatchActive();
} }
} }
@ -635,14 +789,16 @@ void ImGui_ImplRaylib_RenderDrawData(ImDrawData *draw_data) {
rlEnableBackfaceCulling(); rlEnableBackfaceCulling();
} }
void HandleGamepadButtonEvent(ImGuiIO &io, GamepadButton button, ImGuiKey key) { void HandleGamepadButtonEvent(ImGuiIO& io, GamepadButton button, ImGuiKey key)
{
if (IsGamepadButtonPressed(0, button)) if (IsGamepadButtonPressed(0, button))
io.AddKeyEvent(key, true); io.AddKeyEvent(key, true);
else if (IsGamepadButtonReleased(0, button)) else if (IsGamepadButtonReleased(0, button))
io.AddKeyEvent(key, false); io.AddKeyEvent(key, false);
} }
void HandleGamepadStickEvent(ImGuiIO &io, GamepadAxis axis, ImGuiKey negKey, ImGuiKey posKey) { void HandleGamepadStickEvent(ImGuiIO& io, GamepadAxis axis, ImGuiKey negKey, ImGuiKey posKey)
{
constexpr float deadZone = 0.20f; constexpr float deadZone = 0.20f;
float axisValue = GetGamepadAxisMovement(0, axis); float axisValue = GetGamepadAxisMovement(0, axis);
@ -651,8 +807,9 @@ void HandleGamepadStickEvent(ImGuiIO &io, GamepadAxis axis, ImGuiKey negKey, ImG
io.AddKeyAnalogEvent(posKey, axisValue > deadZone, axisValue > deadZone ? axisValue : 0); io.AddKeyAnalogEvent(posKey, axisValue > deadZone, axisValue > deadZone ? axisValue : 0);
} }
bool ImGui_ImplRaylib_ProcessEvents(void) { bool ImGui_ImplRaylib_ProcessEvents(void)
ImGuiIO &io = ImGui::GetIO(); {
ImGuiIO& io = ImGui::GetIO();
bool focused = IsWindowFocused(); bool focused = IsWindowFocused();
if (focused != LastFrameFocused) if (focused != LastFrameFocused)
@ -681,27 +838,40 @@ bool ImGui_ImplRaylib_ProcessEvents(void) {
LastSuperPressed = superDown; LastSuperPressed = superDown;
// walk the keymap and check for up and down events // walk the keymap and check for up and down events
for (const auto keyItr : RaylibKeyMap) { for (const auto keyItr : RaylibKeyMap)
{
if (IsKeyReleased(keyItr.first)) if (IsKeyReleased(keyItr.first))
io.AddKeyEvent(keyItr.second, false); io.AddKeyEvent(keyItr.second, false);
else if (IsKeyPressed(keyItr.first)) else if(IsKeyPressed(keyItr.first))
io.AddKeyEvent(keyItr.second, true); io.AddKeyEvent(keyItr.second, true);
} }
if (io.WantCaptureKeyboard) { if (io.WantCaptureKeyboard)
{
// add the text input in order // add the text input in order
unsigned int pressed = GetCharPressed(); unsigned int pressed = GetCharPressed();
while (pressed != 0) { while (pressed != 0)
{
io.AddInputCharacter(pressed); io.AddInputCharacter(pressed);
pressed = GetCharPressed(); pressed = GetCharPressed();
} }
} }
if (!io.WantSetMousePos) { bool processsMouse = focused;
io.AddMousePosEvent((float)GetMouseX(), (float)GetMouseY());
#if defined(RLIMGUI_ALWAYS_TRACK_MOUSE)
processsMouse = true;
#endif
if (processsMouse)
{
if (!io.WantSetMousePos)
{
io.AddMousePosEvent(float(GetMouseX()), float(GetMouseY()));
} }
auto setMouseEvent = [&io](int rayMouse, int imGuiMouse) { auto setMouseEvent = [&io](int rayMouse, int imGuiMouse)
{
if (IsMouseButtonPressed(rayMouse)) if (IsMouseButtonPressed(rayMouse))
io.AddMouseButtonEvent(imGuiMouse, true); io.AddMouseButtonEvent(imGuiMouse, true);
else if (IsMouseButtonReleased(rayMouse)) else if (IsMouseButtonReleased(rayMouse))
@ -718,8 +888,14 @@ bool ImGui_ImplRaylib_ProcessEvents(void) {
Vector2 mouseWheel = GetMouseWheelMoveV(); Vector2 mouseWheel = GetMouseWheelMoveV();
io.AddMouseWheelEvent(mouseWheel.x, mouseWheel.y); io.AddMouseWheelEvent(mouseWheel.x, mouseWheel.y);
} }
}
else
{
io.AddMousePosEvent(std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
}
if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad && IsGamepadAvailable(0)) { if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad && IsGamepadAvailable(0))
{
HandleGamepadButtonEvent(io, GAMEPAD_BUTTON_LEFT_FACE_UP, ImGuiKey_GamepadDpadUp); HandleGamepadButtonEvent(io, GAMEPAD_BUTTON_LEFT_FACE_UP, ImGuiKey_GamepadDpadUp);
HandleGamepadButtonEvent(io, GAMEPAD_BUTTON_LEFT_FACE_RIGHT, ImGuiKey_GamepadDpadRight); HandleGamepadButtonEvent(io, GAMEPAD_BUTTON_LEFT_FACE_RIGHT, ImGuiKey_GamepadDpadRight);
HandleGamepadButtonEvent(io, GAMEPAD_BUTTON_LEFT_FACE_DOWN, ImGuiKey_GamepadDpadDown); HandleGamepadButtonEvent(io, GAMEPAD_BUTTON_LEFT_FACE_DOWN, ImGuiKey_GamepadDpadDown);
@ -741,16 +917,12 @@ bool ImGui_ImplRaylib_ProcessEvents(void) {
HandleGamepadButtonEvent(io, GAMEPAD_BUTTON_MIDDLE_RIGHT, ImGuiKey_GamepadBack); HandleGamepadButtonEvent(io, GAMEPAD_BUTTON_MIDDLE_RIGHT, ImGuiKey_GamepadBack);
// left stick // left stick
HandleGamepadStickEvent(io, GAMEPAD_AXIS_LEFT_X, ImGuiKey_GamepadLStickLeft, HandleGamepadStickEvent(io, GAMEPAD_AXIS_LEFT_X, ImGuiKey_GamepadLStickLeft, ImGuiKey_GamepadLStickRight);
ImGuiKey_GamepadLStickRight); HandleGamepadStickEvent(io, GAMEPAD_AXIS_LEFT_Y, ImGuiKey_GamepadLStickUp, ImGuiKey_GamepadLStickDown);
HandleGamepadStickEvent(io, GAMEPAD_AXIS_LEFT_Y, ImGuiKey_GamepadLStickUp,
ImGuiKey_GamepadLStickDown);
// right stick // right stick
HandleGamepadStickEvent(io, GAMEPAD_AXIS_RIGHT_X, ImGuiKey_GamepadRStickLeft, HandleGamepadStickEvent(io, GAMEPAD_AXIS_RIGHT_X, ImGuiKey_GamepadRStickLeft, ImGuiKey_GamepadRStickRight);
ImGuiKey_GamepadRStickRight); HandleGamepadStickEvent(io, GAMEPAD_AXIS_RIGHT_Y, ImGuiKey_GamepadRStickUp, ImGuiKey_GamepadRStickDown);
HandleGamepadStickEvent(io, GAMEPAD_AXIS_RIGHT_Y, ImGuiKey_GamepadRStickUp,
ImGuiKey_GamepadRStickDown);
} }
return true; return true;

View file

@ -110,11 +110,6 @@ RLIMGUIAPI void rlImGuiBeginInitImGui(void);
/// </summary> /// </summary>
RLIMGUIAPI void rlImGuiEndInitImGui(void); RLIMGUIAPI void rlImGuiEndInitImGui(void);
/// <summary>
/// Forces the font texture atlas to be recomputed and re-cached
/// </summary>
RLIMGUIAPI void rlImGuiReloadFonts(void);
// Advanced Update API // Advanced Update API
/// <summary> /// <summary>
@ -193,7 +188,7 @@ bool rlImGuiImageButton(const char* name, const Texture* image);
/// <param name="image">The texture to draw</param> /// <param name="image">The texture to draw</param>
/// <param name="size">The size of the button</param> /// <param name="size">The size of the button</param>
/// <returns>True if the button was clicked</returns> /// <returns>True if the button was clicked</returns>
RLIMGUIAPI bool rlImGuiImageButtonSize(const char* name, const Texture* image, struct ImVec2 size); RLIMGUIAPI bool rlImGuiImageButtonSize(const char* name, const Texture* image, Vector2 size);
#ifdef __cplusplus #ifdef __cplusplus
} }