diff --git a/CMakeLists.txt b/CMakeLists.txt index e0cf678839..248dfcf6b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,6 +134,13 @@ target_compile_definitions(dusk PRIVATE TARGET_PC AVOID_UB=1 VERSION=0) target_include_directories(dusk PRIVATE include) target_link_libraries(dusk PRIVATE game aurora::main) +add_custom_command(TARGET dusk POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${CMAKE_SOURCE_DIR}/res" + "$/res" + COMMENT "Copying resources" +) + include(extern/aurora/cmake/AuroraCopyRuntimeDLLs.cmake) aurora_copy_runtime_dlls(dusk game) diff --git a/extern/aurora b/extern/aurora index 33ec54347d..37631c3bf3 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 33ec54347df497c3f8c237e5c2b65590fb1807df +Subproject commit 37631c3bf382c1564d3f29c4c3f2dc6cf7617fa9 diff --git a/files.cmake b/files.cmake index 26cae0f1a9..e5b470dde2 100644 --- a/files.cmake +++ b/files.cmake @@ -1344,6 +1344,8 @@ set(DUSK_FILES #src/dusk/m_Do_ext_dusk.cpp src/dusk/imgui/ImGuiConsole.hpp src/dusk/imgui/ImGuiConsole.cpp + src/dusk/imgui/ImGuiEngine.cpp + src/dusk/imgui/ImGuiEngine.hpp src/dusk/imgui/ImGuiMenuGame.cpp src/dusk/imgui/ImGuiMenuGame.hpp src/dusk/imgui/ImGuiMenuTools.cpp diff --git a/res/NotoMono-Regular.ttf b/res/NotoMono-Regular.ttf new file mode 100644 index 0000000000..3560a3a0c8 Binary files /dev/null and b/res/NotoMono-Regular.ttf differ diff --git a/src/dusk/imgui/ImGuiCameraOverlay.cpp b/src/dusk/imgui/ImGuiCameraOverlay.cpp index 58b31fe00f..9d3ef60142 100644 --- a/src/dusk/imgui/ImGuiCameraOverlay.cpp +++ b/src/dusk/imgui/ImGuiCameraOverlay.cpp @@ -26,7 +26,8 @@ namespace dusk { } ImGui::SetNextWindowBgAlpha(0.65f); - ImGui::SetNextWindowSizeConstraints(ImVec2(300, 0), ImVec2(FLT_MAX, FLT_MAX)); + ImGui::SetNextWindowSizeConstraints(ImVec2(300.f * ImGuiScale(), 0), + ImVec2(FLT_MAX, FLT_MAX)); if (!ImGui::Begin("Camera Debug", nullptr, windowFlags)) { ImGui::End(); diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 917b00b237..9bfdb71d38 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -21,6 +21,8 @@ using namespace std::string_literals; using namespace std::string_view_literals; namespace dusk { + float ImGuiScale() { return ImGui::GetIO().DisplayFramebufferScale.x; } + void ImGuiStringViewText(std::string_view text) { // begin()/end() do not work on MSVC ImGui::TextUnformatted(text.data(), text.data() + text.size()); @@ -47,7 +49,7 @@ namespace dusk { ImVec2 workSize = viewport->WorkSize; ImVec2 windowPos; ImVec2 windowPosPivot; - constexpr float padding = 10.0f; + const float padding = 10.0f * ImGuiScale(); windowPos.x = (corner & 1) != 0 ? (workPos.x + workSize.x - padding) : (workPos.x + padding); windowPos.y = (corner & 2) != 0 ? (workPos.y + workSize.y - padding) : (workPos.y + padding); windowPosPivot.x = (corner & 1) != 0 ? 1.0f : 0.0f; @@ -173,23 +175,32 @@ namespace dusk { ImGuiConsole::ImGuiConsole() {} void ImGuiConsole::draw() { + if (!m_isLaunchInitialized) { + m_toasts.emplace_back("Press F1 to toggle menu"s, 5.f); + m_isLaunchInitialized = true; + } + if (CheckMenuViewToggle(ImGuiKey_F1, m_isHidden)) { + ShowToasts(); m_menuTools.afterDraw(); return; } + // TODO: we need to be able to render the menu bar & any overlays separately + // The code currently ties them all together, so hiding the menu hides all windows + if (ImGui::BeginMainMenuBar()) { m_menuGame.draw(); m_menuTools.draw(); m_menuEnhancements.draw(); - ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 80.0f); + ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 80.0f * ImGuiScale()); ImGuiIO& io = ImGui::GetIO(); ImGuiStringViewText(fmt::format(FMT_STRING("FPS: {:.2f}\n"), io.Framerate)); ImGui::EndMainMenuBar(); } - + ShowToasts(); m_menuTools.afterDraw(); } @@ -223,4 +234,44 @@ namespace dusk { return "Null"sv; } } + + void ImGuiConsole::ShowToasts() { + if (m_toasts.empty()) { + return; + } + auto& toast = m_toasts.front(); + const float dt = ImGui::GetIO().DeltaTime; + toast.remain -= dt; + toast.current += dt; + + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + const ImVec2 workPos = viewport->WorkPos; + const ImVec2 workSize = viewport->WorkSize; + constexpr float padding = 10.0f; + const ImVec2 windowPos{workPos.x + workSize.x / 2, workPos.y + workSize.y - padding}; + ImGui::SetNextWindowPos(windowPos, ImGuiCond_Always, ImVec2{0.5f, 1.f}); + + const float alpha = std::min({toast.remain, toast.current, 1.f}); + ImGui::SetNextWindowBgAlpha(alpha * 0.65f); + ImVec4 textColor = ImGui::GetStyleColorVec4(ImGuiCol_Text); + textColor.w *= alpha; + ImVec4 borderColor = ImGui::GetStyleColorVec4(ImGuiCol_Border); + borderColor.w *= alpha; + ImGui::PushStyleColor(ImGuiCol_Text, textColor); + ImGui::PushStyleColor(ImGuiCol_Border, borderColor); + if (ImGui::Begin("Toast", nullptr, + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | + ImGuiWindowFlags_NoMove)) + { + ImGuiStringViewText(toast.message); + } + ImGui::End(); + ImGui::PopStyleColor(2); + + if (toast.remain <= 0.f) { + m_toasts.pop_front(); + } + } } diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 2cb887f904..db67c2a1cf 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -2,41 +2,56 @@ #define DUSK_IMGUI_HPP #include +#include #include -#include "imgui.h" +#include "ImGuiMenuEnhancements.hpp" #include "ImGuiMenuGame.hpp" #include "ImGuiMenuTools.hpp" -#include "ImGuiMenuEnhancements.hpp" +#include "imgui.h" namespace dusk { - class ImGuiConsole { - public: - ImGuiConsole(); - void draw(); +class ImGuiConsole { +public: + ImGuiConsole(); + void draw(); - ImGuiMenuTools::CollisionViewSettings& getCollisionViewSettings() { return m_menuTools.getCollisionViewSettings(); } + ImGuiMenuTools::CollisionViewSettings& getCollisionViewSettings() { + return m_menuTools.getCollisionViewSettings(); + } - static bool CheckMenuViewToggle(ImGuiKey key, bool& active); + static bool CheckMenuViewToggle(ImGuiKey key, bool& active); - private: - bool m_isHidden = false; +private: + struct Toast { + std::string message; + float remain; + float current = 0.f; + Toast(std::string message, float duration) noexcept : message(std::move(message)), + remain(duration) {} + }; - ImGuiMenuGame m_menuGame; - ImGuiMenuTools m_menuTools; - ImGuiMenuEnhancements m_menuEnhancements; - }; + bool m_isHidden = true; + bool m_isLaunchInitialized = false; + std::deque m_toasts; + ImGuiMenuGame m_menuGame; + ImGuiMenuTools m_menuTools; + ImGuiMenuEnhancements m_menuEnhancements; - extern ImGuiConsole g_imguiConsole; + void ShowToasts(); +}; - std::string_view backend_name(AuroraBackend backend); - std::string BytesToString(size_t bytes); - void SetOverlayWindowLocation(int corner); - bool ShowCornerContextMenu(int& corner, int avoidCorner); - void ImGuiStringViewText(std::string_view text); - void ImGuiBeginGroupPanel(const char* name, const ImVec2& size); - void ImGuiEndGroupPanel(); -} +extern ImGuiConsole g_imguiConsole; + +std::string_view backend_name(AuroraBackend backend); +std::string BytesToString(size_t bytes); +void SetOverlayWindowLocation(int corner); +bool ShowCornerContextMenu(int& corner, int avoidCorner); +void ImGuiStringViewText(std::string_view text); +void ImGuiBeginGroupPanel(const char* name, const ImVec2& size); +void ImGuiEndGroupPanel(); +float ImGuiScale(); +} // namespace dusk void DuskDebugPad(); diff --git a/src/dusk/imgui/ImGuiControllerOverlay.cpp b/src/dusk/imgui/ImGuiControllerOverlay.cpp index 0da82ac878..306bace22a 100644 --- a/src/dusk/imgui/ImGuiControllerOverlay.cpp +++ b/src/dusk/imgui/ImGuiControllerOverlay.cpp @@ -13,8 +13,6 @@ namespace dusk { ImGui::TextUnformatted(text.c_str()); } - static inline float GetScale() { return ImGui::GetCurrentContext()->CurrentDpiScale; } - void ImGuiMenuGame::windowInputViewer() { if (!m_showInputViewer) { return; @@ -35,7 +33,7 @@ namespace dusk { ImGui::SetNextWindowBgAlpha(0.65f); if (ImGui::Begin("Input Viewer", nullptr, windowFlags)) { - float scale = GetScale(); + float scale = ImGuiScale(); if (!m_controllerName.empty()) { TextCenter(m_controllerName); ImGui::Separator(); diff --git a/src/dusk/imgui/ImGuiEngine.cpp b/src/dusk/imgui/ImGuiEngine.cpp new file mode 100644 index 0000000000..4e2097cf3d --- /dev/null +++ b/src/dusk/imgui/ImGuiEngine.cpp @@ -0,0 +1,201 @@ +#include "ImGuiEngine.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "dusk/logging.h" + +#ifdef IMGUI_ENABLE_FREETYPE +#include "misc/freetype/imgui_freetype.h" +#endif + +namespace dusk { +namespace { +std::string GetAssetPath(const char* assetName) { + const char* basePath = SDL_GetBasePath(); + if (basePath != nullptr && basePath[0] != '\0') { + return std::string(basePath) + "res/" + assetName; + } + return std::string("res/") + assetName; +} + +bool AssetExists(const std::string& path) { + SDL_PathInfo pathInfo{}; + return SDL_GetPathInfo(path.c_str(), &pathInfo) && pathInfo.type == SDL_PATHTYPE_FILE; +} +} // namespace + +ImFont* ImGuiEngine::fontNormal; +ImFont* ImGuiEngine::fontLarge; +ImTextureID ImGuiEngine::duskIcon; + +void ImGuiEngine_Initialize(float scale) { + ImGui::GetCurrentContext(); + ImGuiIO& io = ImGui::GetIO(); + io.Fonts->Clear(); + + const std::string fontPath = GetAssetPath("NotoMono-Regular.ttf"); + const bool hasFontFile = AssetExists(fontPath); + + ImFontConfig fontConfig{}; + fontConfig.SizePixels = std::floor(15.f * scale); + snprintf(static_cast(fontConfig.Name), sizeof(fontConfig.Name), + "Noto Mono Regular, %dpx", static_cast(fontConfig.SizePixels)); + ImGuiEngine::fontNormal = + hasFontFile ? + io.Fonts->AddFontFromFileTTF(fontPath.c_str(), fontConfig.SizePixels, &fontConfig) : + nullptr; + if (ImGuiEngine::fontNormal == nullptr) { + if (hasFontFile) { + DuskLog.warn("Failed to load font '{}': {}", fontPath, SDL_GetError()); + } + ImGuiEngine::fontNormal = io.Fonts->AddFontDefault(&fontConfig); + } + + fontConfig.SizePixels = std::floor(26.f * scale); +#ifdef IMGUI_ENABLE_FREETYPE + fontConfig.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Bold; + snprintf(static_cast(fontConfig.Name), sizeof(fontConfig.Name), "Noto Mono Bold, %dpx", + static_cast(fontConfig.SizePixels)); +#else + snprintf(static_cast(fontConfig.Name), sizeof(fontConfig.Name), + "Noto Mono Regular, %dpx", static_cast(fontConfig.SizePixels)); +#endif + ImGuiEngine::fontLarge = + hasFontFile ? + io.Fonts->AddFontFromFileTTF(fontPath.c_str(), fontConfig.SizePixels, &fontConfig) : + nullptr; + if (ImGuiEngine::fontLarge == nullptr) { + if (hasFontFile) { + DuskLog.warn("Failed to load font '{}': {}", fontPath, SDL_GetError()); + } + ImGuiEngine::fontLarge = io.Fonts->AddFontDefault(&fontConfig); + } + + auto& style = ImGui::GetStyle(); + style = {}; // Reset sizes + style.WindowPadding = ImVec2(15, 15); + style.WindowRounding = 5.0f; + style.FrameBorderSize = 1.f; + style.FramePadding = ImVec2(5, 5); + style.FrameRounding = 4.0f; + style.ItemSpacing = ImVec2(12, 8); + style.ItemInnerSpacing = ImVec2(8, 6); + style.IndentSpacing = 25.0f; + style.ScrollbarSize = 15.0f; + style.ScrollbarRounding = 9.0f; + style.GrabMinSize = 5.0f; + style.GrabRounding = 3.0f; + style.PopupBorderSize = 1.f; + style.PopupRounding = 7.0; + style.TabBorderSize = 1.f; + style.TabRounding = 3.f; + + auto* colors = style.Colors; + colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.36f, 0.42f, 0.47f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f); + colors[ImGuiCol_ChildBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); + colors[ImGuiCol_Border] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.12f, 0.20f, 0.28f, 1.00f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.09f, 0.12f, 0.14f, 1.00f); + colors[ImGuiCol_TitleBg] = ImVec4(0.09f, 0.12f, 0.14f, 0.65f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.39f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.18f, 0.22f, 0.25f, 1.00f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.09f, 0.21f, 0.31f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.37f, 0.61f, 1.00f, 1.00f); + colors[ImGuiCol_Button] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.20f, 0.25f, 0.29f, 0.55f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f); + colors[ImGuiCol_TabHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_TabActive] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); + colors[ImGuiCol_TabUnfocused] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f); + colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f); + colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); + + style.ScaleAllSizes(scale); +} + +Icon GetIcon() { + const std::string iconPath = GetAssetPath("icon.png"); + if (!AssetExists(iconPath)) { + return {}; + } + + SDL_Surface* loadedSurface = SDL_LoadPNG(iconPath.c_str()); + if (loadedSurface == nullptr) { + DuskLog.warn("Failed to load icon '{}': {}", iconPath, SDL_GetError()); + return {}; + } + + SDL_Surface* rgbaSurface = SDL_ConvertSurface(loadedSurface, SDL_PIXELFORMAT_RGBA32); + SDL_DestroySurface(loadedSurface); + if (rgbaSurface == nullptr) { + DuskLog.warn("Failed to convert icon '{}': {}", iconPath, SDL_GetError()); + return {}; + } + + const auto iconWidth = static_cast(rgbaSurface->w); + const auto iconHeight = static_cast(rgbaSurface->h); + const size_t rowSize = static_cast(iconWidth) * 4; + const size_t size = rowSize * static_cast(iconHeight); + auto ptr = std::make_unique(size); + for (uint32_t row = 0; row < iconHeight; ++row) { + const auto* src = static_cast(rgbaSurface->pixels) + + static_cast(row) * static_cast(rgbaSurface->pitch); + auto* dst = ptr.get() + static_cast(row) * rowSize; + std::memcpy(dst, src, rowSize); + } + + SDL_DestroySurface(rgbaSurface); + return Icon{ + std::move(ptr), + size, + iconWidth, + iconHeight, + }; +} + +void ImGuiEngine_AddTextures() { + auto icon = GetIcon(); + if (icon.data == nullptr || icon.width == 0 || icon.height == 0) { + ImGuiEngine::duskIcon = 0; + return; + } + + ImGuiEngine::duskIcon = aurora_imgui_add_texture(icon.width, icon.height, icon.data.get()); +} +} // namespace dusk diff --git a/src/dusk/imgui/ImGuiEngine.hpp b/src/dusk/imgui/ImGuiEngine.hpp new file mode 100644 index 0000000000..18e49c2a47 --- /dev/null +++ b/src/dusk/imgui/ImGuiEngine.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include "imgui.h" +#include "misc/cpp/imgui_stdlib.h" + +namespace dusk { +class ImGuiEngine { +public: + static ImFont* fontNormal; + static ImFont* fontLarge; + static ImTextureID duskIcon; +}; + +void ImGuiEngine_Initialize(float scale); +void ImGuiEngine_AddTextures(); + +struct Icon { + std::unique_ptr data; + size_t size; + uint32_t width; + uint32_t height; +}; +Icon GetIcon(); +} // namespace dusk diff --git a/src/dusk/imgui/ImGuiMapLoader.cpp b/src/dusk/imgui/ImGuiMapLoader.cpp index 8d11c0673b..4baf48bdab 100644 --- a/src/dusk/imgui/ImGuiMapLoader.cpp +++ b/src/dusk/imgui/ImGuiMapLoader.cpp @@ -17,7 +17,8 @@ namespace dusk { ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; ImGui::SetNextWindowBgAlpha(0.65f); - ImGui::SetNextWindowSizeConstraints(ImVec2(300, 0), ImVec2(FLT_MAX, FLT_MAX)); + ImGui::SetNextWindowSizeConstraints(ImVec2(300.f * ImGuiScale(), 0), + ImVec2(FLT_MAX, FLT_MAX)); if (!ImGui::Begin("Map Loader", &m_showMapLoader, windowFlags)) { ImGui::End(); diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 00b287cc41..398e64de3a 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -84,13 +84,14 @@ namespace dusk { } static void drawVirtualStick(const char* id, const ImVec2& stick) { - ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 5, ImGui::GetCursorPos().y)); + float scale = ImGuiScale(); + ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 5 * scale, ImGui::GetCursorPos().y)); - ImGui::BeginChild(id, ImVec2(80, 80)); + ImGui::BeginChild(id, ImVec2(80 * scale, 80 * scale)); ImDrawList* dl = ImGui::GetWindowDrawList(); ImVec2 p = ImGui::GetCursorScreenPos(); - float radius = ImGui::GetCurrentContext()->CurrentDpiScale * 30.0f; + float radius = 30.0f * scale; ImVec2 pos = ImVec2(p.x + radius, p.y + radius); constexpr ImU32 stickGray = IM_COL32(150, 150, 150, 255); @@ -98,7 +99,7 @@ namespace dusk { constexpr ImU32 red = IM_COL32(230, 0, 0, 255); dl->AddCircleFilled(pos, radius, stickGray, 8); - dl->AddCircleFilled(ImVec2(pos.x + stick.x * (radius), pos.y + -stick.y * (radius)), 3, red); + dl->AddCircleFilled(ImVec2(pos.x + stick.x * (radius), pos.y + -stick.y * (radius)), 3 * scale, red); ImGui::EndChild(); } @@ -139,12 +140,14 @@ namespace dusk { } } + float scale = ImGuiScale(); ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize; ImGui::SetNextWindowBgAlpha(0.65f); - ImGui::SetNextWindowSizeConstraints(ImVec2(850, 400), ImVec2(850, 400)); + ImGui::SetNextWindowSizeConstraints(ImVec2(850 * scale, 400 * scale), + ImVec2(850 * scale, 400 * scale)); if (!ImGui::Begin("Controller Config", &m_showControllerConfig, windowFlags)) { ImGui::End(); @@ -225,9 +228,9 @@ namespace dusk { } // buttons panel - constexpr float uiButtonSize = 40; + const float uiButtonSize = 40 * scale; - ImGuiBeginGroupPanel("Buttons", ImVec2(150, 20)); + ImGuiBeginGroupPanel("Buttons", ImVec2(150 * scale, 20 * scale)); u32 buttonCount; PADButtonMapping* btnMappingList = PADGetButtonMappings(m_controllerConfig.m_selectedPort, &buttonCount); @@ -251,7 +254,7 @@ namespace dusk { dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(btnMappingList[i].nativeButton), i); } bool pressed = ImGui::Button(dispName.c_str(), - ImVec2(100.0f, 20.0f)); + ImVec2(100.0f * scale, 20.0f * scale)); if (pressed) { m_controllerConfig.m_isReading = true; @@ -268,7 +271,7 @@ namespace dusk { uint32_t axisCount; PADAxisMapping* axisMappingList = PADGetAxisMappings(m_controllerConfig.m_selectedPort, &axisCount); - ImGuiBeginGroupPanel("Triggers", ImVec2(150, 20)); + ImGuiBeginGroupPanel("Triggers", ImVec2(150 * scale, 20 * scale)); PADAxis triggers[] = {PAD_AXIS_TRIGGER_L, PAD_AXIS_TRIGGER_R}; if (axisMappingList != nullptr) { @@ -291,7 +294,7 @@ namespace dusk { dispName = fmt::format("{0}##-{1}", PADGetNativeAxisName(axisMappingList[trigger].nativeAxis), trigger); } bool pressed = ImGui::Button(dispName.c_str(), - ImVec2(100.0f, 20.0f)); + ImVec2(100.0f * scale, 20.0f * scale)); if (pressed) { m_controllerConfig.m_isReading = true; @@ -308,7 +311,7 @@ namespace dusk { int port = m_controllerConfig.m_selectedPort; // main stick panel - ImGuiBeginGroupPanel("Control Stick", ImVec2(150, 20)); + ImGuiBeginGroupPanel("Control Stick", ImVec2(150 * scale, 20 * scale)); drawVirtualStick("##mainStick", ImVec2{ mDoCPd_c::getStickX(port), mDoCPd_c::getStickY(port) }); @@ -345,7 +348,7 @@ namespace dusk { dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis); } } - bool pressed = ImGui::Button(dispName.c_str(), ImVec2(100.0f, 20.0f)); + bool pressed = ImGui::Button(dispName.c_str(), ImVec2(100.0f * scale, 20.0f * scale)); if (pressed) { m_controllerConfig.m_isReading = true; @@ -372,7 +375,7 @@ namespace dusk { ImGui::SameLine(); // sub stick panel - ImGuiBeginGroupPanel("C Stick", ImVec2(150, 20)); + ImGuiBeginGroupPanel("C Stick", ImVec2(150 * scale, 20 * scale)); drawVirtualStick("##subStick", ImVec2{ mDoCPd_c::getSubStickX(port), mDoCPd_c::getSubStickY(port) }); @@ -409,7 +412,7 @@ namespace dusk { dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis); } } - bool pressed = ImGui::Button(fmt::format("{0}##sub{1}", dispName, label).c_str(), ImVec2(100.0f, 20.0f)); + bool pressed = ImGui::Button(fmt::format("{0}##sub{1}", dispName, label).c_str(), ImVec2(100.0f * scale, 20.0f * scale)); if (pressed) { m_controllerConfig.m_isReading = true; @@ -434,7 +437,7 @@ namespace dusk { ImGui::SameLine(); // Triggers Panel - ImGuiBeginGroupPanel("Triggers", ImVec2(150, 20)); + ImGuiBeginGroupPanel("Triggers", ImVec2(150 * scale, 20 * scale)); if (deadZones != nullptr) { ImGui::Text("L Threshold"); @@ -460,7 +463,7 @@ namespace dusk { ImGui::SameLine(); // Options panel - ImGuiBeginGroupPanel("Options", ImVec2(150, 20)); + ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, 20 * scale)); if (deadZones != nullptr) { ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones); diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 40bb3fa1ec..ca855a00cb 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -131,6 +131,9 @@ namespace dusk { BytesToString(stats->lastVertSize + stats->lastUniformSize + stats->lastIndexSize + stats->lastStorageSize + stats->lastTextureUploadSize))); + + // TODO: persist to config + ShowCornerContextMenu(m_debugOverlayCorner, m_cameraOverlayCorner); } ImGui::End(); } diff --git a/src/dusk/imgui/ImGuiMenuTools.hpp b/src/dusk/imgui/ImGuiMenuTools.hpp index 66c820dd78..42fcbdbe42 100644 --- a/src/dusk/imgui/ImGuiMenuTools.hpp +++ b/src/dusk/imgui/ImGuiMenuTools.hpp @@ -38,7 +38,7 @@ namespace dusk { private: bool m_showDebugOverlay = false; - int m_debugOverlayCorner = 0; // top-left + int m_debugOverlayCorner = 2; // bottom-left bool m_showCameraOverlay = false; int m_cameraOverlayCorner = 3; diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 03ff6b8c0f..3c51875bd5 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -48,6 +48,7 @@ #include "dusk/logging.h" #include "dusk/time.h" #include "dusk/main.h" +#include "dusk/imgui/ImGuiEngine.hpp" #include #include @@ -225,6 +226,10 @@ static AuroraBackend ParseAuroraBackend(const std::string& value) { exit(1); } +static void aurora_imgui_init_callback(const AuroraWindowSize* size) { + dusk::ImGuiEngine_Initialize(size->scale); +} + // ========================================================================= // PC ENTRY POINT // ========================================================================= @@ -270,6 +275,7 @@ int game_main(int argc, char* argv[]) { config.mem1Size = 256 * 1024 * 1024; config.mem2Size = 24 * 1024 * 1024; config.allowJoystickBackgroundEvents = true; + config.imGuiInitCallback = &aurora_imgui_init_callback; auroraInfo = aurora_initialize(argc, argv, &config);