diff --git a/extern/aurora b/extern/aurora index b78bbf3f58..552be91d68 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit b78bbf3f585a6ccce81366f9b0bc1681e366ae15 +Subproject commit 552be91d68d57a911dac5ba2b718b8fd61ac7e37 diff --git a/res/rml/overlay.rcss b/res/rml/overlay.rcss index 2cf8c8a8de..cf90037f57 100644 --- a/res/rml/overlay.rcss +++ b/res/rml/overlay.rcss @@ -79,15 +79,11 @@ toast heading > row { toast message { display: flex; flex-flow: column; - align-items: start; - justify-content: start; gap: 8dp; } toast message row { display: flex; - align-items: start; - justify-content: start; } toast message row.muted { diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index fa5f849dbe..a18d257690 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -10,7 +10,7 @@ #include "fmt/format.h" #include "ImGuiConsole.hpp" -#include "dusk/ui/ui.hpp" +#include "ImGuiEngine.hpp" #include "JSystem/JUtility/JUTGamePad.h" #include "SDL3/SDL_mouse.h" #include "dusk/audio/DuskAudioSystem.h" @@ -20,6 +20,7 @@ #include "dusk/livesplit.h" #include "dusk/main.h" #include "dusk/settings.h" +#include "dusk/ui/ui.hpp" #include "f_pc/f_pc_manager.h" #include "f_pc/f_pc_name.h" #include "m_Do/m_Do_controller_pad.h" @@ -302,6 +303,67 @@ namespace dusk { UpdateDragScroll(); + // Show message when Aurora backend is Null + if (aurora_get_backend() == BACKEND_NULL) { + auto& io = ImGui::GetIO(); + ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x, io.DisplaySize.y)); + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowBgAlpha(0.65f); + ImGui::Begin("Pre Launch Window", nullptr, + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoBringToFrontOnFocus); + ImGui::NewLine(); + if (ImGuiEngine::duskLogo) { + const auto& windowSize = ImGui::GetWindowSize(); + ImGui::NewLine(); + float iconSize = 150.f; + float width = iconSize * 2.5f; + ImGui::SameLine(windowSize.x / 2 - width + (width / 2)); + ImGui::Image(ImGuiEngine::duskLogo, ImVec2{width, iconSize}); + } else { + ImGui::PushFont(ImGuiEngine::fontExtraLarge); + ImGuiTextCenter("Dusk"); + ImGui::PopFont(); + } + ImGui::PushFont(ImGuiEngine::fontLarge); + ImGuiTextCenter("Failed to initialize any graphics backend"); + const auto& style = ImGui::GetStyle(); + const auto retrySize = ImGui::CalcTextSize("Retry (Auto backend)"); + const auto quitSize = ImGui::CalcTextSize("Quit"); + float buttonsWidth = quitSize.x + style.FramePadding.x * 2.0f; + if constexpr (SupportsProcessRestart) { + buttonsWidth += retrySize.x + style.FramePadding.x * 2.0f + style.ItemSpacing.x; + } +#if DUSK_CAN_OPEN_DATA_FOLDER + const auto openSize = ImGui::CalcTextSize("Open Data Folder"); + buttonsWidth += openSize.x + style.FramePadding.x * 2.0f + style.ItemSpacing.x; +#endif + ImGui::NewLine(); + ImGui::SetCursorPosX( + ImMax(style.WindowPadding.x, (ImGui::GetWindowSize().x - buttonsWidth) * 0.5f)); + if constexpr (SupportsProcessRestart) { + if (ImGui::Button("Retry (Auto backend)")) { + getSettings().backend.graphicsBackend.setValue("auto"); + config::Save(); + RestartRequested = true; + IsRunning = false; + } + ImGui::SameLine(); + } +#if DUSK_CAN_OPEN_DATA_FOLDER + if (ImGui::Button("Open Data Folder")) { + OpenDataFolder(); + } + ImGui::SameLine(); +#endif + if (ImGui::Button("Quit")) { + IsRunning = false; + } + ImGui::PopFont(); + ImGui::End(); + } + m_menuGame.windowControllerConfig(); m_menuGame.windowInputViewer(); m_menuGame.drawSpeedrunTimerOverlay(); diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 1aee9df373..1b6964c2cc 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -2,13 +2,16 @@ #define DUSK_IMGUI_HPP #include +#include #include #include +#include #include #include "ImGuiMenuGame.hpp" #include "ImGuiMenuTools.hpp" +#include "dusk/main.h" #include "imgui.h" union SDL_Event; @@ -23,7 +26,7 @@ public: void PreDraw(); void PostDraw(); - static bool CheckMenuViewToggle(ImGuiKey key, bool& active); + static bool CheckMenuViewToggle(ImGuiKey key, bool& active); void AddToast(std::string_view message, float duration = 3.f); private: @@ -72,4 +75,24 @@ float ImGuiScale(); void DuskDebugPad(); +#if defined(_WIN32) || \ + (defined(__APPLE__) && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_MACCATALYST) || \ + (defined(__linux__) && !defined(__ANDROID__)) +#define DUSK_CAN_OPEN_DATA_FOLDER 1 + +namespace fs = std::filesystem; + +static void OpenDataFolder() { + const std::string path = fs::absolute(dusk::ConfigPath).generic_string(); +#if defined(_WIN32) + const std::string url = std::string("file:///") + path; +#else + const std::string url = std::string("file://") + path; +#endif + (void)SDL_OpenURL(url.c_str()); +} +#else +#define DUSK_CAN_OPEN_DATA_FOLDER 0 +#endif + #endif // DUSK_IMGUI_HPP diff --git a/src/dusk/imgui/ImGuiEngine.cpp b/src/dusk/imgui/ImGuiEngine.cpp index 4b6a7fb531..3e742de853 100644 --- a/src/dusk/imgui/ImGuiEngine.cpp +++ b/src/dusk/imgui/ImGuiEngine.cpp @@ -219,7 +219,7 @@ void ImGuiEngine_AddTextures() { ImGuiEngine::orgIcon = AddTexture("org-icon.png"); } if (ImGuiEngine::duskLogo == 0) { - ImGuiEngine::duskLogo = AddTexture("logo.png"); + ImGuiEngine::duskLogo = AddTexture("logo-mascot.png"); } } } // namespace dusk diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index d3c062e0f0..2326ba4fa4 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -23,24 +23,6 @@ #include #endif -#if defined(_WIN32) || (defined(__APPLE__) && !TARGET_OS_IOS && !TARGET_OS_MACCATALYST) || (defined(__linux__) && !defined(__ANDROID__)) -#define DUSK_CAN_OPEN_DATA_FOLDER 1 - -namespace fs = std::filesystem; - -static void OpenDataFolder() { - const std::string path = fs::absolute(dusk::ConfigPath).generic_string(); -#if defined(_WIN32) - const std::string url = std::string("file:///") + path; -#else - const std::string url = std::string("file://") + path; -#endif - (void)SDL_OpenURL(url.c_str()); -} -#else -#define DUSK_CAN_OPEN_DATA_FOLDER 0 -#endif - namespace aurora::gx { extern bool enableLodBias; } diff --git a/src/dusk/ui/overlay.cpp b/src/dusk/ui/overlay.cpp index c26ff51481..6e401934ce 100644 --- a/src/dusk/ui/overlay.cpp +++ b/src/dusk/ui/overlay.cpp @@ -21,53 +21,58 @@ const Rml::String kDocumentSource = R"RML( )RML"; +constexpr std::array, 3> kAutoSaveLayers{{ + {"inner", "res/org-icon-inner.png"}, + {"outer", "res/org-icon-outer.png"}, + {"center", "res/org-icon-center.png"}, +}}; + Rml::Element* create_toast(Rml::Element* parent, const Toast& toast) { if (toast.type == "autosave") { - Rml::Factory::InstanceElementText(parent, R"RML( - - - - - -)RML"); - return parent->GetFirstChild(); - } else { - auto* elem = append(parent, "toast"); - if (!toast.type.empty()) { - elem->SetClass(toast.type, true); + auto* logo = append(parent, "logo"); + for (const auto [cls, src] : kAutoSaveLayers) { + auto* img = append(logo, "img"); + img->SetClass(cls, true); + img->SetAttribute("src", src); } - { - auto* heading = append(elem, "heading"); - if (toast.title.starts_with("<")) { - heading->SetInnerRML(toast.title); - } else { - auto* span = append(heading, "span"); - span->SetInnerRML(toast.title); - } - if (toast.type == "achievement") { - auto* icon = append(heading, "icon"); - icon->SetClass("trophy", true); - mDoAud_seStartMenu(kSoundAchievementUnlock); - } else if (toast.type == "controller") { - auto* icon = append(heading, "icon"); - icon->SetClass("controller", true); - } - } - { - auto* message = append(elem, "message"); - if (toast.content.starts_with("<")) { - message->SetInnerRML(toast.content); - } else { - auto* span = append(message, "span"); - span->SetInnerRML(toast.content); - } - } - { - auto* progress = append(elem, "progress"); - progress->SetAttribute("value", 1.f); - } - return elem; + return logo; } + + auto* elem = append(parent, "toast"); + if (!toast.type.empty()) { + elem->SetClass(toast.type, true); + } + { + auto* heading = append(elem, "heading"); + if (toast.title.starts_with("<")) { + heading->SetInnerRML(toast.title); + } else { + auto* span = append(heading, "span"); + span->SetInnerRML(toast.title); + } + if (toast.type == "achievement") { + auto* icon = append(heading, "icon"); + icon->SetClass("trophy", true); + mDoAud_seStartMenu(kSoundAchievementUnlock); + } else if (toast.type == "controller") { + auto* icon = append(heading, "icon"); + icon->SetClass("controller", true); + } + } + { + auto* message = append(elem, "message"); + if (toast.content.starts_with("<")) { + message->SetInnerRML(toast.content); + } else { + auto* span = append(message, "span"); + span->SetInnerRML(toast.content); + } + } + { + auto* progress = append(elem, "progress"); + progress->SetAttribute("value", 1.f); + } + return elem; } } // namespace diff --git a/src/dusk/ui/ui.cpp b/src/dusk/ui/ui.cpp index 7b0f792c2b..d664a0ce6a 100644 --- a/src/dusk/ui/ui.cpp +++ b/src/dusk/ui/ui.cpp @@ -117,6 +117,10 @@ const char* connection_state_icon(SDL_JoystickConnectionState state) noexcept { } void handle_event(const SDL_Event& event) noexcept { + if (!aurora::rmlui::is_initialized()) { + return; + } + if (event.type == SDL_EVENT_GAMEPAD_ADDED) { auto* gamepad = SDL_GetGamepadFromID(event.gdevice.which); if (SDL_GamepadConnected(gamepad)) { @@ -205,6 +209,10 @@ Document* top_document() noexcept { } void update() noexcept { + if (!aurora::rmlui::is_initialized()) { + return; + } + input::update_input(); for (const auto& doc : sDocumentStack) { doc->update(); diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index b171b9733d..f7b6cd8865 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -600,6 +600,21 @@ int game_main(int argc, char* argv[]) { dusk::audio::SetEnableReverb(dusk::getSettings().audio.enableReverb); dusk::audio::EnableHrtf = dusk::getSettings().audio.enableHrtf; + // Run ImGui UI loop if Aurora couldn't initialize a backend + if (auroraInfo.backend == BACKEND_NULL) { + launchUILoop(); + dusk::ShutdownCrashReporting(); + dusk::ShutdownFileLogging(); + fflush(stdout); + fflush(stderr); +#ifdef DUSK_DISCORD + dusk::discord::shutdown(); +#endif + dusk::ui::shutdown(); + aurora_shutdown(); + return 0; + } + dusk::ui::initialize(); dusk::ui::push_document(std::make_unique(), true, true); dusk::ui::push_document(std::make_unique(), false);