From 6b906538dc4c2b7d71a2d482f19e0a14ec00e3d5 Mon Sep 17 00:00:00 2001 From: Graham Pentheny Date: Thu, 10 Jul 2025 11:11:54 -0400 Subject: [PATCH] WIP DearImGui conversion --- .../imgui/backends/imgui_impl_opengl2.cpp | 346 ++++++++++ .../imgui/backends/imgui_impl_opengl2.h | 43 ++ RecastDemo/Source/ConvexVolumeTool.cpp | 4 + RecastDemo/Source/CrowdTool.cpp | 12 + RecastDemo/Source/NavMeshPruneTool.cpp | 4 + RecastDemo/Source/NavMeshTesterTool.cpp | 4 + RecastDemo/Source/OffMeshConnectionTool.cpp | 4 + RecastDemo/Source/Sample.cpp | 2 + RecastDemo/Source/Sample_SoloMesh.cpp | 12 +- RecastDemo/Source/Sample_TempObstacles.cpp | 13 +- RecastDemo/Source/Sample_TileMesh.cpp | 14 + RecastDemo/Source/TestCase.cpp | 5 + RecastDemo/Source/ValueHistory.cpp | 4 + RecastDemo/Source/main.cpp | 635 ++++++++++-------- RecastDemo/premake5.lua | 62 +- 15 files changed, 862 insertions(+), 302 deletions(-) create mode 100644 RecastDemo/Contrib/imgui/backends/imgui_impl_opengl2.cpp create mode 100644 RecastDemo/Contrib/imgui/backends/imgui_impl_opengl2.h diff --git a/RecastDemo/Contrib/imgui/backends/imgui_impl_opengl2.cpp b/RecastDemo/Contrib/imgui/backends/imgui_impl_opengl2.cpp new file mode 100644 index 00000000..afcafe82 --- /dev/null +++ b/RecastDemo/Contrib/imgui/backends/imgui_impl_opengl2.cpp @@ -0,0 +1,346 @@ +// dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline) +// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). +// Missing features or Issues: +// [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). + +// 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 + +// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** +// **Prefer using the code in imgui_impl_opengl3.cpp** +// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. +// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more +// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might +// confuse your GPU driver. +// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API. + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL2_CreateFontsTexture() and ImGui_ImplOpenGL2_DestroyFontsTexture(). +// 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. +// 2024-06-28: OpenGL: ImGui_ImplOpenGL2_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL2_DestroyFontsTexture(). (#7748) +// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. +// 2021-12-08: OpenGL: Fixed mishandling of the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86. +// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). +// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) +// 2021-01-03: OpenGL: Backup, setup and restore GL_SHADE_MODEL state, disable GL_STENCIL_TEST and disable GL_NORMAL_ARRAY client state to increase compatibility with legacy OpenGL applications. +// 2020-01-23: OpenGL: Backup, setup and restore GL_TEXTURE_ENV to increase compatibility with legacy OpenGL applications. +// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. +// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display. +// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. +// 2018-08-03: OpenGL: Disabling/restoring GL_LIGHTING and GL_COLOR_MATERIAL to increase compatibility with legacy OpenGL applications. +// 2018-06-08: Misc: Extracted imgui_impl_opengl2.cpp/.h away from the old combined GLFW/SDL+OpenGL2 examples. +// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. +// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplOpenGL2_RenderDrawData() in the .h file so you can call it yourself. +// 2017-09-01: OpenGL: Save and restore current polygon mode. +// 2016-09-10: OpenGL: Uploading font texture as RGBA32 to increase compatibility with users shaders (not ideal). +// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle. + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_impl_opengl2.h" +#include // intptr_t + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used +#pragma clang diagnostic ignored "-Wnonportable-system-include-path" +#endif + +// Include OpenGL header (without an OpenGL loader) requires a bit of fiddling +#if defined(_WIN32) && !defined(APIENTRY) +#define APIENTRY __stdcall // It is customary to use APIENTRY for OpenGL function pointer declarations on all platforms. Additionally, the Windows OpenGL header needs APIENTRY. +#endif +#if defined(_WIN32) && !defined(WINGDIAPI) +#define WINGDIAPI __declspec(dllimport) // Some Windows OpenGL headers need this +#endif +#if defined(__APPLE__) +#define GL_SILENCE_DEPRECATION +#include +#else +#include +#endif + +// [Debugging] +//#define IMGUI_IMPL_OPENGL_DEBUG +#ifdef IMGUI_IMPL_OPENGL_DEBUG +#include +#define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check +#else +#define GL_CALL(_CALL) _CALL // Call without error check +#endif + +// OpenGL data +struct ImGui_ImplOpenGL2_Data +{ + ImGui_ImplOpenGL2_Data() { memset((void*)this, 0, sizeof(*this)); } +}; + +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData() +{ + return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; +} + +// Functions +bool ImGui_ImplOpenGL2_Init() +{ + ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + + // Setup backend capabilities flags + ImGui_ImplOpenGL2_Data* bd = IM_NEW(ImGui_ImplOpenGL2_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_opengl2"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + return true; +} + +void ImGui_ImplOpenGL2_Shutdown() +{ + ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + + ImGui_ImplOpenGL2_DestroyDeviceObjects(); + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures); + IM_DELETE(bd); +} + +void ImGui_ImplOpenGL2_NewFrame() +{ + ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); + IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplOpenGL2_Init()?"); + IM_UNUSED(bd); +} + +static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height) +{ + // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // In order to composite our output buffer we need to preserve alpha + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glEnable(GL_SCISSOR_TEST); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glEnable(GL_TEXTURE_2D); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glShadeModel(GL_SMOOTH); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!), + // you may need to backup/reset/restore other state, e.g. for current shader using the commented lines below. + // (DO NOT MODIFY THIS FILE! Add the code in your calling function) + // GLint last_program; + // glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); + // glUseProgram(0); + // ImGui_ImplOpenGL2_RenderDrawData(...); + // glUseProgram(last_program) + // There are potentially many more states you could need to clear/setup that we can't access from default headers. + // e.g. glBindBuffer(GL_ARRAY_BUFFER, 0), glDisable(GL_TEXTURE_CUBE_MAP). + + // Setup viewport, orthographic projection matrix + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + GL_CALL(glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height)); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(draw_data->DisplayPos.x, draw_data->DisplayPos.x + draw_data->DisplaySize.x, draw_data->DisplayPos.y + draw_data->DisplaySize.y, draw_data->DisplayPos.y, -1.0f, +1.0f); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); +} + +// OpenGL2 Render function. +// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly. +// This is in order to be able to run within an OpenGL engine that doesn't do so. +void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) +{ + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if (fb_width == 0 || fb_height == 0) + return; + + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplOpenGL2_UpdateTexture(tex); + + // Backup GL state + GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); + GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); + GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); + GLint last_shade_model; glGetIntegerv(GL_SHADE_MODEL, &last_shade_model); + GLint last_tex_env_mode; glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &last_tex_env_mode); + glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); + + // Setup desired GL state + ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height); + + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + + // Render command lists + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* draw_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; + const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; + glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, pos))); + glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, uv))); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, col))); + + for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback) + { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) + if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height); + else + pcmd->UserCallback(draw_list, pcmd); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; + + // Apply scissor/clipping rectangle (Y is inverted in OpenGL) + glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)); + + // Bind texture, Draw + glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()); + glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset); + } + } + } + + // Restore modified GL state + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glPopAttrib(); + glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]); + glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); + glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); + glShadeModel(last_shade_model); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, last_tex_env_mode); +} + +void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex) +{ + if (tex->Status == ImTextureStatus_WantCreate) + { + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == 0 && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + const void* pixels = tex->GetPixels(); + GLuint gl_texture_id = 0; + + // Upload texture to graphics system + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + GLint last_texture; + GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); + GL_CALL(glGenTextures(1, &gl_texture_id)); + GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_texture_id)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)); + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); + GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); + + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)gl_texture_id); + tex->SetStatus(ImTextureStatus_OK); + + // Restore state + GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture)); + } + else if (tex->Status == ImTextureStatus_WantUpdates) + { + // Update selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region. + GLint last_texture; + GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); + + GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID; + GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_tex_id)); + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->Width)); + for (ImTextureRect& r : tex->Updates) + GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x, r.y, r.w, r.h, GL_RGBA, GL_UNSIGNED_BYTE, tex->GetPixelsAt(r.x, r.y))); + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); + GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture)); // Restore state + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantDestroy) + { + GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID; + glDeleteTextures(1, &gl_tex_id); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); + } +} + +bool ImGui_ImplOpenGL2_CreateDeviceObjects() +{ + return true; +} + +void ImGui_ImplOpenGL2_DestroyDeviceObjects() +{ + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + { + tex->SetStatus(ImTextureStatus_WantDestroy); + ImGui_ImplOpenGL2_UpdateTexture(tex); + } +} + +//----------------------------------------------------------------------------- + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/RecastDemo/Contrib/imgui/backends/imgui_impl_opengl2.h b/RecastDemo/Contrib/imgui/backends/imgui_impl_opengl2.h new file mode 100644 index 00000000..014a03ac --- /dev/null +++ b/RecastDemo/Contrib/imgui/backends/imgui_impl_opengl2.h @@ -0,0 +1,43 @@ +// dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline) +// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). +// Missing features or Issues: +// [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). + +// 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 + +// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** +// **Prefer using the code in imgui_impl_opengl3.cpp** +// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. +// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more +// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might +// confuse your GPU driver. +// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API. + +#pragma once +#include "imgui.h" // IMGUI_IMPL_API +#ifndef IMGUI_DISABLE + +// Follow "Getting Started" link and check examples/ folder to learn about using backends! +IMGUI_IMPL_API bool ImGui_ImplOpenGL2_Init(); +IMGUI_IMPL_API void ImGui_ImplOpenGL2_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplOpenGL2_NewFrame(); +IMGUI_IMPL_API void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data); + +// Called by Init/NewFrame/Shutdown +IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyDeviceObjects(); + +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex); + +#endif // #ifndef IMGUI_DISABLE diff --git a/RecastDemo/Source/ConvexVolumeTool.cpp b/RecastDemo/Source/ConvexVolumeTool.cpp index 6dfccd4d..5f2b72fe 100644 --- a/RecastDemo/Source/ConvexVolumeTool.cpp +++ b/RecastDemo/Source/ConvexVolumeTool.cpp @@ -116,6 +116,7 @@ bool pointInPoly(int nvert, const float* verts, const float* p) void ConvexVolumeTool::handleMenu() { +#if 0 imguiSlider("Shape Height", &boxHeight, 0.1f, 20.0f, 0.1f); imguiSlider("Shape Descent", &boxDescent, 0.1f, 20.0f, 0.1f); imguiSlider("Poly Offset", &polyOffset, 0.0f, 10.0f, 0.1f); @@ -157,6 +158,7 @@ void ConvexVolumeTool::handleMenu() numPoints = 0; numHull = 0; } +#endif } void ConvexVolumeTool::handleClick(const float* /*s*/, const float* p, bool shift) @@ -294,6 +296,7 @@ void ConvexVolumeTool::handleRender() void ConvexVolumeTool::handleRenderOverlay(double* /*proj*/, double* /*model*/, int* view) { +#if 0 // Tool help const int h = view[3]; if (!numPoints) @@ -320,4 +323,5 @@ void ConvexVolumeTool::handleRenderOverlay(double* /*proj*/, double* /*model*/, "The shape will be convex hull of all added points.", imguiRGBA(255, 255, 255, 192)); } +#endif } diff --git a/RecastDemo/Source/CrowdTool.cpp b/RecastDemo/Source/CrowdTool.cpp index 7ad82a7e..cd401230 100644 --- a/RecastDemo/Source/CrowdTool.cpp +++ b/RecastDemo/Source/CrowdTool.cpp @@ -506,7 +506,9 @@ void CrowdToolState::handleRenderOverlay(double* proj, double* model, int* view) if (m_targetRef && gluProject((GLdouble)m_targetPos[0], (GLdouble)m_targetPos[1], (GLdouble)m_targetPos[2], model, proj, view, &x, &y, &z)) { +#if 0 imguiDrawText((int)x, (int)(y + 25), IMGUI_ALIGN_CENTER, "TARGET", imguiRGBA(0, 0, 0, 220)); +#endif } char label[32]; @@ -540,7 +542,9 @@ void CrowdToolState::handleRenderOverlay(double* proj, double* model, int* view) { const float heuristic = node->total; // - node->cost; snprintf(label, 32, "%.2f", heuristic); +#if 0 imguiDrawText((int)x, (int)y + 15, IMGUI_ALIGN_CENTER, label, imguiRGBA(0, 0, 0, 220)); +#endif } } } @@ -562,7 +566,9 @@ void CrowdToolState::handleRenderOverlay(double* proj, double* model, int* view) if (gluProject((GLdouble)pos[0], (GLdouble)pos[1] + h, (GLdouble)pos[2], model, proj, view, &x, &y, &z)) { snprintf(label, 32, "%d", i); +#if 0 imguiDrawText((int)x, (int)y + 15, IMGUI_ALIGN_CENTER, label, imguiRGBA(0, 0, 0, 220)); +#endif } } } @@ -596,7 +602,9 @@ void CrowdToolState::handleRenderOverlay(double* proj, double* model, int* view) &z)) { snprintf(label, 32, "%.3f", ag->neis[j].dist); +#if 0 imguiDrawText((int)x, (int)y + 15, IMGUI_ALIGN_CENTER, label, imguiRGBA(255, 255, 255, 220)); +#endif } } } @@ -842,6 +850,7 @@ void CrowdTool::reset() {} void CrowdTool::handleMenu() { +#if 0 if (!m_state) { return; } CrowdToolParams* params = m_state->getToolParams(); @@ -923,6 +932,7 @@ void CrowdTool::handleMenu() if (imguiCheck("Show Detail All", params->m_showDetailAll)) { params->m_showDetailAll = !params->m_showDetailAll; } imguiUnindent(); } +#endif } void CrowdTool::handleClick(const float* s, const float* p, bool shift) @@ -1001,6 +1011,7 @@ void CrowdTool::handleRender() {} void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view) { +#if 0 rcIgnoreUnused(model); rcIgnoreUnused(proj); @@ -1037,4 +1048,5 @@ void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view) imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "- RUNNING -", imguiRGBA(255, 32, 16, 255)); } else { imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "- PAUSED -", imguiRGBA(255, 255, 255, 128)); } +#endif } diff --git a/RecastDemo/Source/NavMeshPruneTool.cpp b/RecastDemo/Source/NavMeshPruneTool.cpp index a18fab40..4356fb42 100644 --- a/RecastDemo/Source/NavMeshPruneTool.cpp +++ b/RecastDemo/Source/NavMeshPruneTool.cpp @@ -225,6 +225,7 @@ void NavMeshPruneTool::handleMenu() return; } +#if 0 if (imguiButton("Clear Selection")) { flags->clearAllFlags(); @@ -236,6 +237,7 @@ void NavMeshPruneTool::handleMenu() delete flags; flags = nullptr; } +#endif } void NavMeshPruneTool::handleClick(const float* s, const float* p, bool shift) @@ -323,5 +325,7 @@ void NavMeshPruneTool::handleRender() void NavMeshPruneTool::handleRenderOverlay(double* /*proj*/, double* /*model*/, int* view) { +#if 0 imguiDrawText(280, view[3] - 40, IMGUI_ALIGN_LEFT, "LMB: Click fill area.", imguiRGBA(255, 255, 255, 192)); +#endif } diff --git a/RecastDemo/Source/NavMeshTesterTool.cpp b/RecastDemo/Source/NavMeshTesterTool.cpp index 4f8a2f5c..10a0732c 100644 --- a/RecastDemo/Source/NavMeshTesterTool.cpp +++ b/RecastDemo/Source/NavMeshTesterTool.cpp @@ -214,6 +214,7 @@ void NavMeshTesterTool::init(Sample* sample) void NavMeshTesterTool::handleMenu() { +#if 0 if (imguiCheck("Pathfind Follow", m_toolMode == TOOLMODE_PATHFIND_FOLLOW)) { m_toolMode = TOOLMODE_PATHFIND_FOLLOW; @@ -419,6 +420,7 @@ void NavMeshTesterTool::handleMenu() imguiUnindent(); imguiSeparator(); +#endif } void NavMeshTesterTool::handleClick(const float* /*s*/, const float* p, bool shift) @@ -1482,6 +1484,7 @@ void NavMeshTesterTool::handleRender() void NavMeshTesterTool::handleRenderOverlay(double* proj, double* model, int* view) { +#if 0 GLdouble x, y, z; // Draw start and end point labels @@ -1502,6 +1505,7 @@ void NavMeshTesterTool::handleRenderOverlay(double* proj, double* model, int* vi IMGUI_ALIGN_LEFT, "LMB+SHIFT: Set start location LMB: Set end location", imguiRGBA(255, 255, 255, 192)); +#endif } void NavMeshTesterTool::drawAgent(const float* pos, float r, float h, float c, const unsigned int col) diff --git a/RecastDemo/Source/OffMeshConnectionTool.cpp b/RecastDemo/Source/OffMeshConnectionTool.cpp index 60681f32..55511b78 100644 --- a/RecastDemo/Source/OffMeshConnectionTool.cpp +++ b/RecastDemo/Source/OffMeshConnectionTool.cpp @@ -54,6 +54,7 @@ void OffMeshConnectionTool::reset() void OffMeshConnectionTool::handleMenu() { +#if 0 if (imguiCheck("One Way", !bidir)) { bidir = false; @@ -62,6 +63,7 @@ void OffMeshConnectionTool::handleMenu() { bidir = true; } +#endif } void OffMeshConnectionTool::handleClick(const float* /*rayStartPos*/, const float* rayHitPos, bool shift) @@ -145,6 +147,7 @@ void OffMeshConnectionTool::handleRender() void OffMeshConnectionTool::handleRenderOverlay(double* proj, double* model, int* view) { +#if 0 GLdouble x, y, z; // Draw start and end point labels @@ -173,4 +176,5 @@ void OffMeshConnectionTool::handleRenderOverlay(double* proj, double* model, int "LMB: Set connection end point and finish.", imguiRGBA(255, 255, 255, 192)); } +#endif } diff --git a/RecastDemo/Source/Sample.cpp b/RecastDemo/Source/Sample.cpp index 46739379..46a1a537 100644 --- a/RecastDemo/Source/Sample.cpp +++ b/RecastDemo/Source/Sample.cpp @@ -201,6 +201,7 @@ void Sample::resetCommonSettings() void Sample::handleCommonSettings() { +#if 0 imguiLabel("Rasterization"); imguiSlider("Cell Size", &cellSize, 0.1f, 1.0f, 0.01f); imguiSlider("Cell Height", &cellHeight, 0.1f, 1.0f, 0.01f); @@ -270,6 +271,7 @@ void Sample::handleCommonSettings() imguiSlider("Max Sample Error", &detailSampleMaxError, 0.0f, 16.0f, 1.0f); imguiSeparator(); +#endif } void Sample::handleClick(const float* rayStartPos, const float* rayHitPos, bool shift) diff --git a/RecastDemo/Source/Sample_SoloMesh.cpp b/RecastDemo/Source/Sample_SoloMesh.cpp index f6e91815..ec8967b4 100644 --- a/RecastDemo/Source/Sample_SoloMesh.cpp +++ b/RecastDemo/Source/Sample_SoloMesh.cpp @@ -67,6 +67,7 @@ void Sample_SoloMesh::handleSettings() { handleCommonSettings(); +#if 0 imguiSeparator(); imguiIndent(); @@ -92,10 +93,12 @@ void Sample_SoloMesh::handleSettings() imguiLabel(message); imguiSeparator(); +#endif } void Sample_SoloMesh::handleTools() { +#if 0 const SampleToolType type = !tool ? SampleToolType::NONE : tool->type(); if (imguiCheck("Test Navmesh", type == SampleToolType::NAVMESH_TESTER)) { setTool(new NavMeshTesterTool); } @@ -114,18 +117,22 @@ void Sample_SoloMesh::handleTools() } imguiUnindent(); +#endif } void Sample_SoloMesh::UI_DrawModeOption(const char* name, const DrawMode drawMode, const bool enabled) { +#if 0 if (imguiCheck(name, currentDrawMode == drawMode, enabled)) { currentDrawMode = drawMode; } +#endif } void Sample_SoloMesh::handleDebugMode() { +#if 0 imguiLabel("Draw"); UI_DrawModeOption("Input Mesh", DrawMode::MESH, true); UI_DrawModeOption("Navmesh", DrawMode::NAVMESH, navMesh != nullptr); @@ -144,6 +151,7 @@ void Sample_SoloMesh::handleDebugMode() UI_DrawModeOption("Contours", DrawMode::CONTOURS, contourSet != nullptr); UI_DrawModeOption("Poly Mesh", DrawMode::POLYMESH, polyMesh != nullptr); UI_DrawModeOption("Poly Mesh Detail", DrawMode::POLYMESH_DETAIL, detailMesh != nullptr); +#endif } void Sample_SoloMesh::handleRender() @@ -164,10 +172,10 @@ void Sample_SoloMesh::handleRender() duDebugDrawTriMeshSlope( &debugDraw, inputGeometry->verts.data(), - static_cast(inputGeometry->verts.size()) / 3, + inputGeometry->getVertCount(), inputGeometry->tris.data(), inputGeometry->normals.data(), - static_cast(inputGeometry->tris.size()) / 3, + inputGeometry->getTriCount(), agentMaxSlope, texScale); inputGeometry->drawOffMeshConnections(&debugDraw); diff --git a/RecastDemo/Source/Sample_TempObstacles.cpp b/RecastDemo/Source/Sample_TempObstacles.cpp index 5046eb6a..36412780 100644 --- a/RecastDemo/Source/Sample_TempObstacles.cpp +++ b/RecastDemo/Source/Sample_TempObstacles.cpp @@ -584,12 +584,14 @@ void drawDetailOverlay(const dtTileCache* tileCache, const int tileX, const int GLdouble x, y, z; if (gluProject(static_cast(pos[0]), static_cast(pos[1]), static_cast(pos[2]), model, proj, view, &x, &y, &z)) { +#if 0 snprintf(text, 128, "(%d,%d)/%d", tile->header->tx, tile->header->ty, tile->header->tlayer); imguiDrawText(static_cast(x), static_cast(y) - 25, IMGUI_ALIGN_CENTER, text, imguiRGBA(0, 0, 0, 220)); snprintf(text, 128, "Compressed: %.1f kB", tile->dataSize / 1024.0f); imguiDrawText(static_cast(x), static_cast(y) - 45, IMGUI_ALIGN_CENTER, text, imguiRGBA(0, 0, 0, 128)); snprintf(text, 128, "Raw:%.1fkB", rawSize / 1024.0f); imguiDrawText(static_cast(x), static_cast(y) - 65, IMGUI_ALIGN_CENTER, text, imguiRGBA(0, 0, 0, 128)); +#endif } } } @@ -670,6 +672,7 @@ public: void handleMenu() override { +#if 0 imguiLabel("Highlight Tile Cache"); imguiValue("Click LMB to highlight a tile."); imguiSeparator(); @@ -689,6 +692,7 @@ public: { m_drawType = DRAWDETAIL_MESH; } +#endif } void handleClick(const float* /*s*/, const float* p, bool /*shift*/) override @@ -758,6 +762,7 @@ public: void handleMenu() override { +#if 0 imguiLabel("Create Temp Obstacles"); if (imguiButton("Remove All")) @@ -767,6 +772,7 @@ public: imguiValue("Click LMB to create an obstacle."); imguiValue("Shift+LMB to remove an obstacle."); +#endif } void handleClick(const float* s, const float* p, bool shift) override @@ -811,7 +817,7 @@ Sample_TempObstacles::~Sample_TempObstacles() void Sample_TempObstacles::handleSettings() { Sample::handleCommonSettings(); - +#if 0 if (imguiCheck("Keep Itermediate Results", m_keepInterResults)) { m_keepInterResults = !m_keepInterResults; @@ -894,10 +900,12 @@ void Sample_TempObstacles::handleSettings() imguiUnindent(); imguiSeparator(); +#endif } void Sample_TempObstacles::handleTools() { +#if 0 const SampleToolType type = !tool ? SampleToolType::NONE : tool->type(); if (imguiCheck("Test Navmesh", type == SampleToolType::NAVMESH_TESTER)) @@ -935,6 +943,7 @@ void Sample_TempObstacles::handleTools() } imguiUnindent(); +#endif } void Sample_TempObstacles::handleDebugMode() @@ -972,6 +981,7 @@ void Sample_TempObstacles::handleDebugMode() return; } +#if 0 imguiLabel("Draw"); if (imguiCheck("Input Mesh", m_drawMode == DRAWMODE_MESH, valid[DRAWMODE_MESH])) { @@ -1012,6 +1022,7 @@ void Sample_TempObstacles::handleDebugMode() imguiValue("rebuild some tiles to see"); imguiValue("more debug mode options."); } +#endif } void Sample_TempObstacles::handleRender() diff --git a/RecastDemo/Source/Sample_TileMesh.cpp b/RecastDemo/Source/Sample_TileMesh.cpp index 01e8118d..5934db42 100644 --- a/RecastDemo/Source/Sample_TileMesh.cpp +++ b/RecastDemo/Source/Sample_TileMesh.cpp @@ -94,6 +94,7 @@ public: void handleMenu() override { +#if 0 imguiLabel("Create Tiles"); if (imguiButton("Create All")) { @@ -109,6 +110,7 @@ public: m_sample->removeAllTiles(); } } +#endif } void handleClick(const float* /*s*/, const float* p, bool shift) override @@ -157,6 +159,7 @@ public: void handleRenderOverlay(double* proj, double* model, int* view) override { +#if 0 GLdouble x, y, z; if (m_hitPosSet && gluProject(m_hitPos[0], m_hitPos[1], m_hitPos[2], model, proj, view, &x, &y, &z)) { @@ -175,6 +178,7 @@ public: IMGUI_ALIGN_LEFT, "LMB: Rebuild hit tile. Shift+LMB: Clear hit tile.", imguiRGBA(255, 255, 255, 192)); +#endif } }; @@ -210,6 +214,7 @@ void Sample_TileMesh::cleanup() void Sample_TileMesh::handleSettings() { Sample::handleCommonSettings(); +#if 0 if (imguiCheck("Build All Tiles", buildAll)) { @@ -278,10 +283,12 @@ void Sample_TileMesh::handleSettings() imguiSeparator(); imguiSeparator(); +#endif } void Sample_TileMesh::handleTools() { +#if 0 const SampleToolType type = !tool ? SampleToolType::NONE : tool->type(); if (imguiCheck("Test Navmesh", type == SampleToolType::NAVMESH_TESTER)) @@ -319,18 +326,22 @@ void Sample_TileMesh::handleTools() } imguiUnindent(); +#endif } void Sample_TileMesh::UI_DrawModeOption(const char* name, DrawMode drawMode, bool enabled) { +#if 0 if (imguiCheck(name, this->drawMode == drawMode, enabled)) { this->drawMode = drawMode; } +#endif } void Sample_TileMesh::handleDebugMode() { +#if 0 imguiLabel("Draw"); UI_DrawModeOption("Input Mesh", DrawMode::MESH, true); UI_DrawModeOption("Navmesh", DrawMode::NAVMESH, navMesh != nullptr); @@ -350,6 +361,7 @@ void Sample_TileMesh::handleDebugMode() UI_DrawModeOption("Contours", DrawMode::CONTOURS, contourSet != nullptr); UI_DrawModeOption("Poly Mesh", DrawMode::POLYMESH, polyMesh != nullptr); UI_DrawModeOption("Poly Mesh Detail", DrawMode::POLYMESH_DETAIL, detailPolyMesh != nullptr); +#endif } void Sample_TileMesh::handleRender() @@ -528,6 +540,7 @@ void Sample_TileMesh::handleRender() void Sample_TileMesh::handleRenderOverlay(double* proj, double* model, int* view) { +#if 0 GLdouble x, y, z; // Draw start and end point labels @@ -553,6 +566,7 @@ void Sample_TileMesh::handleRenderOverlay(double* proj, double* model, int* view tool->handleRenderOverlay(proj, model, view); } renderOverlayToolStates(proj, model, view); +#endif } void Sample_TileMesh::handleMeshChanged(InputGeom* geom) diff --git a/RecastDemo/Source/TestCase.cpp b/RecastDemo/Source/TestCase.cpp index 32da4022..d702c3a2 100644 --- a/RecastDemo/Source/TestCase.cpp +++ b/RecastDemo/Source/TestCase.cpp @@ -424,6 +424,7 @@ void TestCase::handleRender() bool TestCase::handleRenderOverlay(double* proj, double* model, int* view) { +#if 0 GLdouble x, y, z; char text[64]; char subtext[64]; @@ -464,6 +465,7 @@ bool TestCase::handleRenderOverlay(double* proj, double* model, int* view) } imguiDrawText((int)x, (int)(y - 25), IMGUI_ALIGN_CENTER, text, col); } + n++; } @@ -500,4 +502,7 @@ bool TestCase::handleRenderOverlay(double* proj, double* model, int* view) imguiEndScrollArea(); return mouseOverMenu; +#else + return false; +#endif } diff --git a/RecastDemo/Source/ValueHistory.cpp b/RecastDemo/Source/ValueHistory.cpp index 44913c83..27b8be9d 100644 --- a/RecastDemo/Source/ValueHistory.cpp +++ b/RecastDemo/Source/ValueHistory.cpp @@ -59,6 +59,7 @@ void GraphParams::setValueRange(float minValue, float maxValue, int numDivisions void drawGraphBackground(const GraphParams* params) { +#if 0 // BG imguiDrawRoundedRect( static_cast(params->x), @@ -94,10 +95,12 @@ void drawGraphBackground(const GraphParams* params) 1.0f, imguiRGBA(0, 0, 0, 64)); } +#endif } void drawGraph(const GraphParams* params, const ValueHistory* graph, int index, const char* label, const unsigned int color) { +#if 0 const float sx = static_cast(params->width - params->padding * 2) / static_cast(graph->getSampleCount()); const float sy = static_cast(params->height - params->padding * 2) / (params->rangeMax - params->rangeMin); const float ox = static_cast(params->x) + static_cast(params->padding); @@ -129,4 +132,5 @@ void drawGraph(const GraphParams* params, const ValueHistory* graph, int index, snprintf(text, 64, "%.2f %s", graph->getAverage(), params->units.c_str()); imguiDrawText(ix + size + 5, iy + 3, IMGUI_ALIGN_LEFT, label, imguiRGBA(255, 255, 255, 192)); imguiDrawText(ix + size + 150, iy + 3, IMGUI_ALIGN_RIGHT, text, imguiRGBA(255, 255, 255, 128)); +#endif } diff --git a/RecastDemo/Source/main.cpp b/RecastDemo/Source/main.cpp index 801f8c7e..da94c604 100644 --- a/RecastDemo/Source/main.cpp +++ b/RecastDemo/Source/main.cpp @@ -17,8 +17,8 @@ // #include "SDL.h" -#include "SDL_opengl.h" #include "SDL_keycode.h" +#include "SDL_opengl.h" #include #include @@ -37,8 +37,10 @@ #include "Sample_TempObstacles.h" #include "Sample_TileMesh.h" #include "TestCase.h" -#include "imgui.h" -#include "imguiRenderGL.h" + +#include +#include +#include #ifdef WIN32 # define snprintf _snprintf @@ -67,7 +69,7 @@ struct AppData int width; int height; SDL_Window* window; - SDL_Renderer* renderer; + SDL_GLContext glContext; // Recast data, samples, and test cases BuildContext buildContext; @@ -110,21 +112,17 @@ struct AppData float rayEnd[3]; // UI - string sampleName = "Choose Sample..."; + int sampleIndex = -1; string meshName = "Choose Mesh..."; // UI state bool showMenu = true; bool showLog = false; bool showTools = true; - bool showLevels = false; - bool showSample = false; bool showTestCases = false; // Window scroll positions. - int propScroll = 0; int logScroll = 0; - int toolsScroll = 0; // Files vector files; @@ -134,6 +132,30 @@ struct AppData // Markers float markerPosition[3] = {0, 0, 0}; bool markerPositionSet = false; + + void resetCamera() + { + const float* bmin = 0; + const float* bmax = 0; + if (inputGeometry) + { + bmin = inputGeometry->getNavMeshBoundsMin(); + bmax = inputGeometry->getNavMeshBoundsMax(); + } + // Reset camera and fog to match the mesh bounds. + if (bmin && bmax) + { + camr = sqrtf(rcSqr(bmax[0] - bmin[0]) + rcSqr(bmax[1] - bmin[1]) + rcSqr(bmax[2] - bmin[2])) / 2; + cameraPos[0] = (bmax[0] + bmin[0]) / 2 + camr; + cameraPos[1] = (bmax[1] + bmin[1]) / 2 + camr; + cameraPos[2] = (bmax[2] + bmin[2]) / 2 + camr; + camr *= 3; + } + cameraEulers[0] = 45; + cameraEulers[1] = -45; + glFogf(GL_FOG_START, camr * 0.1f); + glFogf(GL_FOG_END, camr * 1.25f); + } }; int main(int /*argc*/, char** /*argv*/) @@ -169,27 +191,163 @@ int main(int /*argc*/, char** /*argv*/) app.width = rcMin(displayMode.w, static_cast(static_cast(displayMode.h) * (16.0f / 9.0f))) - 80; app.height = displayMode.h - 80; - int errorCode = SDL_CreateWindowAndRenderer( + // Create the SDL window with OpenGL support + app.window = SDL_CreateWindow( + "My App", + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, app.width, app.height, - SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE, - &app.window, - &app.renderer); + SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); - if (errorCode != 0 || !app.window || !app.renderer) + // Create the OpenGL context + app.glContext = SDL_GL_CreateContext(app.window); + SDL_GL_MakeCurrent(app.window, app.glContext); + + if (!app.window || !app.glContext) { - printf("Could not initialise SDL opengl\nError: %s\n", SDL_GetError()); + printf("Could not initialize SDL opengl\nError: %s\n", SDL_GetError()); return -1; } SDL_SetWindowPosition(app.window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); - if (!imguiRenderGLInit("DroidSans.ttf")) - { - printf("Could not init GUI renderer.\n"); - SDL_Quit(); - return -1; - } + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + io.Fonts->AddFontFromFileTTF("DroidSans.ttf", 16.0f); // Size in pixels + ImGui::PushFont(io.Fonts->Fonts[0]); + ImGui::StyleColorsDark(); + + + + // Set style + float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); + style.FontScaleDpi = main_scale; + style.WindowRounding = 8.0f; + style.FrameRounding = 4.0f; + style.WindowPadding = ImVec2(10, 10); + style.FramePadding = ImVec2(8, 4); + + style.Colors[ImGuiCol_WindowBg] = ImVec4(0.0f, 0.0f, 0.0f, 0.75f); + style.Colors[ImGuiCol_Header] = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); + style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.0f, 0.0f, 0.0f, 0.75f); + style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(1.0f, 1.0f, 1.0f, 0.25f); + style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(1.0f, 0.75f, 0, 0.75f); + style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(1.0f, 0.75f, 0, 0.37f); + + style.Colors[ImGuiCol_Button] = ImVec4(0.5f, 0.5f, 0.5f, 96.0f / 255.0f); + style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.5f, 0.5f, 0.5f, 196.0f / 255.0f); + //style.Colors[ImGuiCol_ButtonHovered] = ImVec4(1.0f, 196.0f / 255.0f, 0, 96.0f / 255.0f); + + /* + /// 0 = FLAT APPEARENCE + /// 1 = MORE "3D" LOOK + int is3D = 1; + + style.Colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f); + style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.73f, 0.73f, 0.73f, 0.35f); + + style.Colors[ImGuiCol_ChildBg] = ImVec4(0.0f, 0.0f, 0.0f, 0.75f); + style.Colors[ImGuiCol_WindowBg] = ImVec4(0.0f, 0.0f, 0.0f, 0.75f); + style.Colors[ImGuiCol_PopupBg] = ImVec4(0.0f, 0.0f, 0.0f, 0.75f); + + style.Colors[ImGuiCol_Border] = ImVec4(0.12f, 0.12f, 0.12f, 0.71f); + style.Colors[ImGuiCol_BorderShadow] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); + + style.Colors[ImGuiCol_FrameBg] = ImVec4(0.42f, 0.42f, 0.42f, 0.54f); + style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.42f, 0.42f, 0.42f, 0.40f); + style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.56f, 0.56f, 0.56f, 0.67f); + + style.Colors[ImGuiCol_TitleBg] = ImVec4(0.19f, 0.19f, 0.19f, 1.00f); + style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f); + style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.17f, 0.17f, 0.17f, 0.90f); + + style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.335f, 0.335f, 0.335f, 1.000f); + + style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.24f, 0.24f, 0.24f, 0.53f); + style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); + style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.52f, 0.52f, 0.52f, 1.00f); + style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.76f, 0.76f, 0.76f, 1.00f); + + style.Colors[ImGuiCol_CheckMark] = ImVec4(0.65f, 0.65f, 0.65f, 1.00f); + + style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.52f, 0.52f, 0.52f, 1.00f); + style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.64f, 0.64f, 0.64f, 1.00f); + + style.Colors[ImGuiCol_Button] = ImVec4(0.54f, 0.54f, 0.54f, 0.35f); + style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.52f, 0.52f, 0.52f, 0.59f); + style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.76f, 0.76f, 0.76f, 1.00f); + + style.Colors[ImGuiCol_Header] = ImVec4(0.38f, 0.38f, 0.38f, 1.00f); + style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.47f, 0.47f, 0.47f, 1.00f); + style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.76f, 0.76f, 0.76f, 0.77f); + + style.Colors[ImGuiCol_Separator] = ImVec4(0.000f, 0.000f, 0.000f, 0.137f); + style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.700f, 0.671f, 0.600f, 0.290f); + style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.702f, 0.671f, 0.600f, 0.674f); + + style.Colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f); + style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + + style.Colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); + style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + + style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); + style.Colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + style.Colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + style.Colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + style.Colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + + style.PopupRounding = 3; + style.WindowPadding = ImVec2(4, 4); + style.FramePadding = ImVec2(6, 4); + style.ItemSpacing = ImVec2(6, 2); + style.ScrollbarSize = 18; + style.WindowBorderSize = 1; + style.ChildBorderSize = 1; + style.PopupBorderSize = 1; + style.FrameBorderSize = is3D; + style.WindowRounding = 3; + style.ChildRounding = 3; + style.FrameRounding = 3; + style.ScrollbarRounding = 2; + style.GrabRounding = 3; + + #ifdef IMGUI_HAS_DOCK + style.TabBorderSize = is3D; + style.TabRounding = 3; + + colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.38f, 0.38f, 0.38f, 1.00f); + colors[ImGuiCol_Tab] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); + colors[ImGuiCol_TabHovered] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f); + colors[ImGuiCol_TabActive] = ImVec4(0.33f, 0.33f, 0.33f, 1.00f); + colors[ImGuiCol_TabUnfocused] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); + colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.33f, 0.33f, 0.33f, 1.00f); + colors[ImGuiCol_DockingPreview] = ImVec4(0.85f, 0.85f, 0.85f, 0.28f); + + if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + style.WindowRounding = 0.0f; + style.Colors[ImGuiCol_WindowBg].w = 1.0f; + } + #endif + */ + + // Setup Platform/Renderer backends + ImGui_ImplSDL2_InitForOpenGL(app.window, app.glContext); + ImGui_ImplOpenGL2_Init(); + + ImGuiWindowFlags staticWindowFlags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoCollapse; app.prevFrameTime = SDL_GetTicks(); @@ -204,19 +362,47 @@ int main(int /*argc*/, char** /*argv*/) glEnable(GL_CULL_FACE); glDepthFunc(GL_LEQUAL); + + + //---------------------------------------------------------------------------- + scanDirectory(app.meshesFolder, ".obj", app.files); + app.meshName = app.files[0]; + app.inputGeometry = new InputGeom; + app.inputGeometry->load(&app.buildContext, app.meshesFolder + "/" + app.meshName); + + app.sampleIndex = 0; + app.sample = g_samples[0].create(); + app.sample->setContext(&app.buildContext); + app.sample->handleMeshChanged(app.inputGeometry); + + // Reset camera and fog to match the mesh bounds. + const float* bmin = app.inputGeometry->getNavMeshBoundsMin(); + const float* bmax = app.inputGeometry->getNavMeshBoundsMax(); + app.camr = sqrtf(rcSqr(bmax[0] - bmin[0]) + rcSqr(bmax[1] - bmin[1]) + rcSqr(bmax[2] - bmin[2])) / 2; + app.cameraPos[0] = (bmax[0] + bmin[0]) / 2 + app.camr; + app.cameraPos[1] = (bmax[1] + bmin[1]) / 2 + app.camr; + app.cameraPos[2] = (bmax[2] + bmin[2]) / 2 + app.camr; + app.camr *= 3; + app.cameraEulers[0] = 45; + app.cameraEulers[1] = -45; + glFogf(GL_FOG_START, app.camr * 0.1f); + glFogf(GL_FOG_END, app.camr * 1.25f); + //---------------------------------------------------------------------------- + + bool done = false; while (!done) { // Handle input events. - int mouseScroll = 0; bool processHitTest = false; bool processHitTestShift = false; // Per frame input - + app.mouseOverMenu = ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow); SDL_Event event; while (SDL_PollEvent(&event)) { + ImGui_ImplSDL2_ProcessEvent(&event); switch (event.type) { case SDL_KEYDOWN: @@ -227,8 +413,6 @@ int main(int /*argc*/, char** /*argv*/) done = true; break; case SDLK_t: - app.showLevels = false; - app.showSample = false; app.showTestCases = true; app.files.clear(); scanDirectory(app.testCasesFolder, ".txt", app.files); @@ -262,11 +446,7 @@ int main(int /*argc*/, char** /*argv*/) break; case SDL_MOUSEWHEEL: - if (app.mouseOverMenu) - { - mouseScroll += event.wheel.y; - } - else + if (!app.mouseOverMenu) { app.scrollZoom += static_cast(event.wheel.y); } @@ -355,16 +535,6 @@ int main(int /*argc*/, char** /*argv*/) } } - unsigned char mouseButtonMask = 0; - if (SDL_GetMouseState(0, 0) & SDL_BUTTON_LMASK) - { - mouseButtonMask |= IMGUI_MBUT_LEFT; - } - if (SDL_GetMouseState(0, 0) & SDL_BUTTON_RMASK) - { - mouseButtonMask |= IMGUI_MBUT_RIGHT; - } - Uint32 time = SDL_GetTicks(); float dt = static_cast(time - app.prevFrameTime) / 1000.0f; app.prevFrameTime = time; @@ -476,12 +646,30 @@ int main(int /*argc*/, char** /*argv*/) // Handle keyboard movement. const Uint8* keystate = SDL_GetKeyboardState(NULL); - app.moveFront = rcClamp(app.moveFront + dt * 4 * ((keystate[SDL_SCANCODE_W] || keystate[SDL_SCANCODE_UP]) ? 1.0f : -1.0f), 0.0f, 1.0f); - app.moveLeft = rcClamp(app.moveLeft + dt * 4 * ((keystate[SDL_SCANCODE_A] || keystate[SDL_SCANCODE_LEFT]) ? 1.0f : -1.0f), 0.0f, 1.0f); - app.moveBack = rcClamp(app.moveBack + dt * 4 * ((keystate[SDL_SCANCODE_S] || keystate[SDL_SCANCODE_DOWN]) ? 1.0f : -1.0f), 0.0f, 1.0f); - app.moveRight = rcClamp(app.moveRight + dt * 4 * ((keystate[SDL_SCANCODE_D] || keystate[SDL_SCANCODE_RIGHT]) ? 1.0f : -1.0f), 0.0f, 1.0f); - app.moveUp = rcClamp(app.moveUp + dt * 4 * ((keystate[SDL_SCANCODE_Q] || keystate[SDL_SCANCODE_PAGEUP]) ? 1.0f : -1.0f), 0.0f, 1.0f); - app.moveDown = rcClamp(app.moveDown + dt * 4 * ((keystate[SDL_SCANCODE_E] || keystate[SDL_SCANCODE_PAGEDOWN]) ? 1.0f : -1.0f), 0.0f, 1.0f); + app.moveFront = rcClamp( + app.moveFront + dt * 4 * ((keystate[SDL_SCANCODE_W] || keystate[SDL_SCANCODE_UP]) ? 1.0f : -1.0f), + 0.0f, + 1.0f); + app.moveLeft = rcClamp( + app.moveLeft + dt * 4 * ((keystate[SDL_SCANCODE_A] || keystate[SDL_SCANCODE_LEFT]) ? 1.0f : -1.0f), + 0.0f, + 1.0f); + app.moveBack = rcClamp( + app.moveBack + dt * 4 * ((keystate[SDL_SCANCODE_S] || keystate[SDL_SCANCODE_DOWN]) ? 1.0f : -1.0f), + 0.0f, + 1.0f); + app.moveRight = rcClamp( + app.moveRight + dt * 4 * ((keystate[SDL_SCANCODE_D] || keystate[SDL_SCANCODE_RIGHT]) ? 1.0f : -1.0f), + 0.0f, + 1.0f); + app.moveUp = rcClamp( + app.moveUp + dt * 4 * ((keystate[SDL_SCANCODE_Q] || keystate[SDL_SCANCODE_PAGEUP]) ? 1.0f : -1.0f), + 0.0f, + 1.0f); + app.moveDown = rcClamp( + app.moveDown + dt * 4 * ((keystate[SDL_SCANCODE_E] || keystate[SDL_SCANCODE_PAGEDOWN]) ? 1.0f : -1.0f), + 0.0f, + 1.0f); float keybSpeed = 22.0f; if (SDL_GetModState() & KMOD_SHIFT) @@ -526,7 +714,10 @@ int main(int /*argc*/, char** /*argv*/) app.mouseOverMenu = false; - imguiBeginFrame(app.mousePos[0], app.mousePos[1], mouseButtonMask, mouseScroll); + ImGui_ImplOpenGL2_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + ImGui::NewFrame(); + ImGui::ShowDemoWindow(); if (app.sample) { @@ -543,256 +734,150 @@ int main(int /*argc*/, char** /*argv*/) // Help text. if (app.showMenu) { - const char msg[] = "W/S/A/D: Move RMB: Rotate"; - imguiDrawText(280, app.height - 20, IMGUI_ALIGN_LEFT, msg, imguiRGBA(255, 255, 255, 128)); + ImDrawList* draw_list = ImGui::GetForegroundDrawList(); + draw_list->AddText({280.0f, 20.0f}, IM_COL32(255, 255, 255, 128), "W/A/S/D: Move RMB: Rotate"); } + bool newMeshSelected = false; + bool newSampleSelected = false; + if (app.showMenu) { - if (imguiBeginScrollArea("Properties", app.width - 250 - 10, 10, 250, app.height - 20, &app.propScroll)) + ImGui::SetNextWindowPos(ImVec2(app.width - 250 - 10, 10), ImGuiCond_Always); // Position in screen space + ImGui::SetNextWindowSize(ImVec2(250, app.height - 20), ImGuiCond_Always); // Size of the window + ImGui::Begin("Properties", nullptr, staticWindowFlags); + + ImGui::Checkbox("Show Log", &app.showLog); + ImGui::Checkbox("Show Tools", &app.showTools); + + ImGui::SeparatorText("Input Mesh"); + + // Level selection dialog. + if (ImGui::BeginCombo("##levelCombo", app.meshName.c_str(), 0)) { - app.mouseOverMenu = true; + app.files.clear(); + scanDirectory(app.meshesFolder, ".obj", app.files); + scanDirectory(app.meshesFolder, ".gset", app.files); + + for (const auto& file : app.files) + { + const bool is_selected = (app.meshName == file); + if (ImGui::Selectable(file.c_str(), is_selected) && !is_selected) + { + app.meshName = file; + newMeshSelected = true; + } + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); } - if (imguiCheck("Show Log", app.showLog)) - { - app.showLog = !app.showLog; - } - if (imguiCheck("Show Tools", app.showTools)) - { - app.showTools = !app.showTools; - } - - imguiSeparator(); - imguiLabel("Sample"); - if (imguiButton(app.sampleName.c_str())) - { - if (app.showSample) - { - app.showSample = false; - } - else - { - app.showSample = true; - app.showLevels = false; - app.showTestCases = false; - } - } - - imguiSeparator(); - imguiLabel("Input Mesh"); - if (imguiButton(app.meshName.c_str())) - { - if (app.showLevels) - { - app.showLevels = false; - } - else - { - app.showSample = false; - app.showTestCases = false; - app.showLevels = true; - app.files.clear(); - scanDirectory(app.meshesFolder, ".obj", app.files); - scanDirectory(app.meshesFolder, ".gset", app.files); - } - } if (app.inputGeometry) { - char text[64]; - snprintf( - text, - 64, + ImGui::Text( "Verts: %.1fk Tris: %.1fk", - static_cast(app.inputGeometry->getVertCount()) / 1000.0f, - static_cast(app.inputGeometry->getTriCount()) / 1000.0f); - imguiValue(text); + static_cast(app.inputGeometry->getVertCount()) / 1000.0f, + static_cast(app.inputGeometry->getTriCount()) / 1000.0f); } - imguiSeparator(); - if (app.inputGeometry && app.sample) + ImGui::SeparatorText("Sample"); + + if (ImGui::BeginCombo("##sampleCombo", app.sampleIndex >= 0 ? g_samples[app.sampleIndex].name.c_str() : "Choose Sample...", 0)) { - imguiSeparatorLine(); - - app.sample->handleSettings(); - - if (imguiButton("Build")) + for (int n = 0; n < IM_ARRAYSIZE(g_samples); n++) { - app.buildContext.resetLog(); - if (!app.sample->handleBuild()) + const bool is_selected = (app.sampleIndex == n); + if (ImGui::Selectable(g_samples[n].name.c_str(), is_selected)) { - app.showLog = true; - app.logScroll = 0; + newSampleSelected = !is_selected; + app.sampleIndex = n; } - app.buildContext.dumpLog("Build log %s:", app.meshName.c_str()); - // Clear test. - delete app.testCase; - app.testCase = 0; + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + { + ImGui::SetItemDefaultFocus(); + } } - - imguiSeparator(); + ImGui::EndCombo(); } if (app.sample) { - imguiSeparatorLine(); + if (app.inputGeometry) + { + app.sample->handleSettings(); + + if (ImGui::Button("Build")) + { + app.buildContext.resetLog(); + if (!app.sample->handleBuild()) + { + app.showLog = true; + app.logScroll = 0; + } + app.buildContext.dumpLog("Build log %s:", app.meshName.c_str()); + + // Clear test. + delete app.testCase; + app.testCase = 0; + } + } + + ImGui::SeparatorText("Debug Settings"); app.sample->handleDebugMode(); } - imguiEndScrollArea(); + ImGui::End(); } - // Sample selection dialog. - if (app.showSample) + if (newSampleSelected) { - static int levelScroll = 0; - if (imguiBeginScrollArea( - "Choose sample", - app.width - 10 - 250 - 10 - 200, - app.height - 10 - 250, - 200, - 250, - &levelScroll)) + delete app.sample; + app.sample = g_samples[app.sampleIndex].create(); + app.sample->setContext(&app.buildContext); + if (app.inputGeometry) { - app.mouseOverMenu = true; + app.sample->handleMeshChanged(app.inputGeometry); + app.resetCamera(); } - - Sample* newSample = 0; - for (int i = 0; i < g_nsamples; ++i) - { - if (imguiItem(g_samples[i].name.c_str())) - { - newSample = g_samples[i].create(); - if (newSample) - { - app.sampleName = g_samples[i].name; - } - } - } - if (newSample) - { - delete app.sample; - app.sample = newSample; - app.sample->setContext(&app.buildContext); - if (app.inputGeometry) - { - app.sample->handleMeshChanged(app.inputGeometry); - } - app.showSample = false; - } - - if (app.inputGeometry || app.sample) - { - const float* bmin = 0; - const float* bmax = 0; - if (app.inputGeometry) - { - bmin = app.inputGeometry->getNavMeshBoundsMin(); - bmax = app.inputGeometry->getNavMeshBoundsMax(); - } - // Reset camera and fog to match the mesh bounds. - if (bmin && bmax) - { - app.camr = sqrtf(rcSqr(bmax[0] - bmin[0]) + rcSqr(bmax[1] - bmin[1]) + rcSqr(bmax[2] - bmin[2])) / 2; - app.cameraPos[0] = (bmax[0] + bmin[0]) / 2 + app.camr; - app.cameraPos[1] = (bmax[1] + bmin[1]) / 2 + app.camr; - app.cameraPos[2] = (bmax[2] + bmin[2]) / 2 + app.camr; - app.camr *= 3; - } - app.cameraEulers[0] = 45; - app.cameraEulers[1] = -45; - glFogf(GL_FOG_START, app.camr * 0.1f); - glFogf(GL_FOG_END, app.camr * 1.25f); - } - - imguiEndScrollArea(); } - // Level selection dialog. - if (app.showLevels) + if (newMeshSelected) { - static int levelScroll = 0; - if (imguiBeginScrollArea( - "Choose Level", - app.width - 10 - 250 - 10 - 200, - app.height - 10 - 450, - 200, - 450, - &levelScroll)) + string path = app.meshesFolder + "/" + app.meshName; + + delete app.inputGeometry; + app.inputGeometry = new InputGeom; + if (!app.inputGeometry->load(&app.buildContext, path)) { - app.mouseOverMenu = true; - } - - vector::const_iterator fileIter = app.files.begin(); - vector::const_iterator filesEnd = app.files.end(); - vector::const_iterator levelToLoad = filesEnd; - for (; fileIter != filesEnd; ++fileIter) - { - if (imguiItem(fileIter->c_str())) - { - levelToLoad = fileIter; - } - } - - if (levelToLoad != filesEnd) - { - app.meshName = *levelToLoad; - app.showLevels = false; - - string path = app.meshesFolder + "/" + app.meshName; - delete app.inputGeometry; - app.inputGeometry = new InputGeom; - if (!app.inputGeometry->load(&app.buildContext, path)) - { - delete app.inputGeometry; - app.inputGeometry = nullptr; + app.inputGeometry = nullptr; - // Destroy the sample if it already had geometry loaded, as we've just deleted it! - if (app.sample && app.sample->getInputGeom()) - { - delete app.sample; - app.sample = nullptr; - } - - app.showLog = true; - app.logScroll = 0; - app.buildContext.dumpLog("geom load log %s:", app.meshName.c_str()); - } - if (app.sample && app.inputGeometry) + // Destroy the sample if it already had geometry loaded, as we've just deleted it! + if (app.sample && app.sample->getInputGeom()) { - app.sample->handleMeshChanged(app.inputGeometry); + delete app.sample; + app.sample = nullptr; } - if (app.inputGeometry || app.sample) - { - const float* bmin = 0; - const float* bmax = 0; - if (app.inputGeometry) - { - bmin = app.inputGeometry->getNavMeshBoundsMin(); - bmax = app.inputGeometry->getNavMeshBoundsMax(); - } - // Reset camera and fog to match the mesh bounds. - if (bmin && bmax) - { - app.camr = sqrtf(rcSqr(bmax[0] - bmin[0]) + rcSqr(bmax[1] - bmin[1]) + rcSqr(bmax[2] - bmin[2])) / 2; - app.cameraPos[0] = (bmax[0] + bmin[0]) / 2 + app.camr; - app.cameraPos[1] = (bmax[1] + bmin[1]) / 2 + app.camr; - app.cameraPos[2] = (bmax[2] + bmin[2]) / 2 + app.camr; - app.camr *= 3; - } - app.cameraEulers[0] = 45; - app.cameraEulers[1] = -45; - glFogf(GL_FOG_START, app.camr * 0.1f); - glFogf(GL_FOG_END, app.camr * 1.25f); - } + app.showLog = true; + app.logScroll = 0; + app.buildContext.dumpLog("geom load log %s:", app.meshName.c_str()); + } + app.resetCamera(); + if (app.sample) + { + app.sample->handleMeshChanged(app.inputGeometry); } - - imguiEndScrollArea(); } +#if 0 // Test cases if (app.showTestCases) { @@ -841,7 +926,7 @@ int main(int /*argc*/, char** /*argv*/) newSample = g_samples[i].create(); if (newSample) { - app.sampleName = g_samples[i].name; + app.sampleIndex = i; } } } @@ -924,35 +1009,37 @@ int main(int /*argc*/, char** /*argv*/) imguiEndScrollArea(); } +#endif // Log + static bool auto_scroll = true; if (app.showLog && app.showMenu) { - if (imguiBeginScrollArea("Log", 250 + 20, 10, app.width - 300 - 250, 200, &app.logScroll)) - { - app.mouseOverMenu = true; - } + ImGui::SetNextWindowPos(ImVec2(250 + 20, app.height - 200 - 10), ImGuiCond_Always); // Position in screen space + ImGui::SetNextWindowSize(ImVec2(app.width - 250 - 250 - 20 - 20, 200), ImGuiCond_Always); // Size of the window + ImGui::Begin("Log", nullptr, staticWindowFlags); + for (int i = 0; i < app.buildContext.getLogCount(); ++i) { - imguiLabel(app.buildContext.getLogText(i)); + ImGui::TextUnformatted(app.buildContext.getLogText(i)); } - imguiEndScrollArea(); + + ImGui::End(); } // Left column tools menu if (!app.showTestCases && app.showTools && app.showMenu) { - if (imguiBeginScrollArea("Tools", 10, 10, 250, app.height - 20, &app.toolsScroll)) - { - app.mouseOverMenu = true; - } + ImGui::SetNextWindowPos(ImVec2(10, 10), ImGuiCond_Always); // Position in screen space + ImGui::SetNextWindowSize(ImVec2(250, app.height - 20), ImGuiCond_Always); // Size of the window + ImGui::Begin("Tools", nullptr, staticWindowFlags); if (app.sample) { app.sample->handleTools(); } - imguiEndScrollArea(); + ImGui::End(); } // Marker @@ -974,16 +1061,20 @@ int main(int /*argc*/, char** /*argv*/) glLineWidth(1.0f); } - imguiEndFrame(); - imguiRenderGLDraw(); - glEnable(GL_DEPTH_TEST); + + ImGui::Render(); + ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); SDL_GL_SwapWindow(app.window); } - imguiRenderGLDestroy(); + ImGui_ImplOpenGL2_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); - SDL_Quit(); + SDL_GL_DeleteContext(app.glContext); + SDL_DestroyWindow(app.window); + SDL_Quit(); delete app.sample; delete app.inputGeometry; diff --git a/RecastDemo/premake5.lua b/RecastDemo/premake5.lua index 076fc8c6..28d08a9f 100644 --- a/RecastDemo/premake5.lua +++ b/RecastDemo/premake5.lua @@ -7,15 +7,15 @@ local action = _ACTION or "" local todir = "Build/" .. action workspace "recastnavigation" - configurations { + configurations { "Debug", "Release" } location (todir) - -- Use fast math operations. This is not required, but it speeds up some calculations - -- at the expense of accuracy. Because there are some functions like dtMathIsfinite + -- Use fast math operations. This is not required, but it speeds up some calculations + -- at the expense of accuracy. Because there are some functions like dtMathIsfinite -- that use floating point functions that become undefined behavior when compiled with -- fast-math, we need to conditionally short-circuit these functions. floatingpoint "Fast" @@ -30,7 +30,7 @@ workspace "recastnavigation" filter "configurations:Debug" defines { "DEBUG" } targetdir ( todir .. "/lib/Debug" ) - + -- release configs filter "configurations:Release" defines { "RC_DISABLE_ASSERTS" } @@ -59,7 +59,7 @@ project "DebugUtils" language "C++" cppdialect "C++98" kind "StaticLib" - includedirs { + includedirs { "../DebugUtils/Include", "../Detour/Include", "../DetourTileCache/Include", @@ -74,12 +74,12 @@ project "Detour" language "C++" cppdialect "C++98" kind "StaticLib" - includedirs { - "../Detour/Include" + includedirs { + "../Detour/Include" } - files { - "../Detour/Include/*.h", - "../Detour/Source/*.cpp" + files { + "../Detour/Include/*.h", + "../Detour/Source/*.cpp" } -- linux library cflags and libs filter {"system:linux", "toolset:gcc"} @@ -120,19 +120,19 @@ project "Recast" language "C++" cppdialect "C++98" kind "StaticLib" - includedirs { - "../Recast/Include" + includedirs { + "../Recast/Include" } - files { + files { "../Recast/Include/*.h", - "../Recast/Source/*.cpp" + "../Recast/Source/*.cpp" } project "RecastDemo" language "C++" cppdialect "C++20" -- we don't care about this being compatible in the same way we do with the library code. kind "WindowedApp" - includedirs { + includedirs { "../RecastDemo/Include", "../RecastDemo/Contrib", "../RecastDemo/Contrib/fastlz", @@ -142,11 +142,18 @@ project "RecastDemo" "../DetourTileCache/Include", "../Recast/Include" } + externalincludedirs { + "../RecastDemo/Contrib/imgui", + "../RecastDemo/Contrib/imgui/backends", + } files { "../RecastDemo/Include/*.h", "../RecastDemo/Source/*.cpp", "../RecastDemo/Contrib/fastlz/*.h", - "../RecastDemo/Contrib/fastlz/*.c" + "../RecastDemo/Contrib/fastlz/*.c", + "../RecastDemo/Contrib/imgui/*.cpp", + "../RecastDemo/Contrib/imgui/backends/imgui_impl_sdl2.cpp", + "../RecastDemo/Contrib/imgui/backends/imgui_impl_opengl2.cpp", } -- project dependencies @@ -163,16 +170,16 @@ project "RecastDemo" -- linux library cflags and libs filter "system:linux" - buildoptions { + buildoptions { "`pkg-config --cflags sdl2`", "`pkg-config --cflags gl`", "`pkg-config --cflags glu`", "-Wno-ignored-qualifiers", } - linkoptions { + linkoptions { "`pkg-config --libs sdl2`", "`pkg-config --libs gl`", - "`pkg-config --libs glu`" + "`pkg-config --libs glu`" } filter { "system:linux", "toolset:gcc", "files:*.c" } @@ -185,7 +192,7 @@ project "RecastDemo" includedirs { "../RecastDemo/Contrib/SDL/include" } libdirs { "../RecastDemo/Contrib/SDL/lib/%{cfg.architecture:gsub('x86_64', 'x64')}" } debugdir "../RecastDemo/Bin/" - links { + links { "glu32", "opengl32", "SDL2", @@ -200,8 +207,9 @@ project "RecastDemo" filter "system:macosx" kind "ConsoleApp" -- xcode4 failes to run the project if using WindowedApp includedirs { "Bin/SDL2.framework/Headers" } - links { - "OpenGL.framework", + externalincludedirs { "Bin/SDL2.framework/Headers" } + links { + "OpenGL.framework", "SDL2.framework", "Cocoa.framework", } @@ -215,7 +223,7 @@ project "Tests" exceptionhandling "On" rtti "On" - includedirs { + includedirs { "../DebugUtils/Include", "../Detour/Include", "../DetourCrowd/Include", @@ -226,7 +234,7 @@ project "Tests" "../Tests", "../Tests/Contrib" } - files { + files { "../Tests/*.h", "../Tests/*.hpp", "../Tests/*.cpp", @@ -239,7 +247,7 @@ project "Tests" } -- project dependencies - links { + links { "DebugUtils", "DetourCrowd", "Detour", @@ -266,7 +274,7 @@ project "Tests" "`pkg-config --cflags glu`", "-Wno-parentheses" -- Disable parentheses warning for the Tests target, as Catch's macros generate this everywhere. } - linkoptions { + linkoptions { "`pkg-config --libs sdl2`", "`pkg-config --libs gl`", "`pkg-config --libs glu`", @@ -278,7 +286,7 @@ project "Tests" includedirs { "../RecastDemo/Contrib/SDL/include" } libdirs { "../RecastDemo/Contrib/SDL/lib/%{cfg.architecture:gsub('x86_64', 'x64')}" } debugdir "../RecastDemo/Bin/" - links { + links { "glu32", "opengl32", "SDL2",