diff --git a/assets/loading1.jpeg b/assets/loading1.jpeg new file mode 100755 index 00000000..79cae0dc Binary files /dev/null and b/assets/loading1.jpeg differ diff --git a/assets/loading1.jpg b/assets/loading1.jpg deleted file mode 100644 index b5d7b73f..00000000 Binary files a/assets/loading1.jpg and /dev/null differ diff --git a/assets/loading2.jpeg b/assets/loading2.jpeg new file mode 100755 index 00000000..2403b28a Binary files /dev/null and b/assets/loading2.jpeg differ diff --git a/assets/loading2.jpg b/assets/loading2.jpg deleted file mode 100644 index ed147fcd..00000000 Binary files a/assets/loading2.jpg and /dev/null differ diff --git a/assets/startscreen.mp4 b/assets/startscreen.mp4 index 3faea727..d58bb228 100755 Binary files a/assets/startscreen.mp4 and b/assets/startscreen.mp4 differ diff --git a/include/core/window.hpp b/include/core/window.hpp index 588297e9..3da55977 100644 --- a/include/core/window.hpp +++ b/include/core/window.hpp @@ -37,6 +37,11 @@ public: int getHeight() const { return height; } void setSize(int w, int h) { width = w; height = h; } float getAspectRatio() const { return static_cast(width) / height; } + bool isFullscreen() const { return fullscreen; } + bool isVsyncEnabled() const { return vsync; } + void setFullscreen(bool enable); + void setVsync(bool enable); + void applyResolution(int w, int h); SDL_Window* getSDLWindow() const { return window; } SDL_GLContext getGLContext() const { return glContext; } @@ -48,6 +53,10 @@ private: int width; int height; + int windowedWidth = 0; + int windowedHeight = 0; + bool fullscreen = false; + bool vsync = true; bool shouldCloseFlag = false; }; diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index 352f1956..0e04ed33 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -55,6 +55,11 @@ private: bool showTeleporter = false; bool showEscapeMenu = false; bool showEscapeSettingsNotice = false; + bool showSettingsWindow = false; + bool settingsInit = false; + bool pendingFullscreen = false; + bool pendingVsync = false; + int pendingResIndex = 0; /** * Render player info window @@ -124,6 +129,7 @@ private: void renderVendorWindow(game::GameHandler& gameHandler); void renderTeleporterPanel(); void renderEscapeMenu(); + void renderSettingsWindow(); /** * Inventory screen diff --git a/src/core/window.cpp b/src/core/window.cpp index d62d3b17..f540b2e1 100644 --- a/src/core/window.cpp +++ b/src/core/window.cpp @@ -8,7 +8,11 @@ namespace core { Window::Window(const WindowConfig& config) : config(config) , width(config.width) - , height(config.height) { + , height(config.height) + , windowedWidth(config.width) + , windowedHeight(config.height) + , fullscreen(config.fullscreen) + , vsync(config.vsync) { } Window::~Window() { @@ -68,6 +72,7 @@ bool Window::initialize() { if (SDL_GL_SetSwapInterval(config.vsync ? 1 : 0) != 0) { LOG_WARNING("Failed to set VSync: ", SDL_GetError()); } + vsync = config.vsync; // Initialize GLEW glewExperimental = GL_TRUE; @@ -133,5 +138,54 @@ void Window::pollEvents() { } } +void Window::setFullscreen(bool enable) { + if (!window) return; + if (enable == fullscreen) return; + if (enable) { + windowedWidth = width; + windowedHeight = height; + if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP) != 0) { + LOG_WARNING("Failed to enter fullscreen: ", SDL_GetError()); + return; + } + fullscreen = true; + SDL_GetWindowSize(window, &width, &height); + } else { + if (SDL_SetWindowFullscreen(window, 0) != 0) { + LOG_WARNING("Failed to exit fullscreen: ", SDL_GetError()); + return; + } + fullscreen = false; + SDL_SetWindowSize(window, windowedWidth, windowedHeight); + width = windowedWidth; + height = windowedHeight; + } + glViewport(0, 0, width, height); +} + +void Window::setVsync(bool enable) { + if (SDL_GL_SetSwapInterval(enable ? 1 : 0) != 0) { + LOG_WARNING("Failed to set VSync: ", SDL_GetError()); + return; + } + vsync = enable; +} + +void Window::applyResolution(int w, int h) { + if (!window) return; + if (w <= 0 || h <= 0) return; + if (fullscreen) { + windowedWidth = w; + windowedHeight = h; + return; + } + SDL_SetWindowSize(window, w, h); + width = w; + height = h; + windowedWidth = w; + windowedHeight = h; + glViewport(0, 0, width, height); +} + } // namespace core } // namespace wowee diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index a0cd7dba..14da8980 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -82,6 +82,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { renderGossipWindow(gameHandler); renderVendorWindow(gameHandler); renderEscapeMenu(); + renderSettingsWindow(); // World map (M key toggle handled inside) renderWorldMap(gameHandler); @@ -355,6 +356,7 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) { if (showEscapeMenu) { showEscapeMenu = false; showEscapeSettingsNotice = false; + showSettingsWindow = false; } else if (showTeleporter) { showTeleporter = false; } else if (gameHandler.isCasting()) { @@ -1757,7 +1759,9 @@ void GameScreen::renderEscapeMenu() { core::Application::getInstance().shutdown(); } if (ImGui::Button("Settings", ImVec2(-1, 0))) { - showEscapeSettingsNotice = true; + showEscapeSettingsNotice = false; + showSettingsWindow = true; + settingsInit = false; } if (showEscapeSettingsNotice) { @@ -1768,4 +1772,79 @@ void GameScreen::renderEscapeMenu() { ImGui::End(); } +// ============================================================ +// Settings Window +// ============================================================ + +void GameScreen::renderSettingsWindow() { + if (!showSettingsWindow) return; + + auto* window = core::Application::getInstance().getWindow(); + if (!window) return; + + static const int kResolutions[][2] = { + {1280, 720}, + {1600, 900}, + {1920, 1080}, + {2560, 1440}, + {3840, 2160}, + }; + static const int kResCount = sizeof(kResolutions) / sizeof(kResolutions[0]); + + if (!settingsInit) { + pendingFullscreen = window->isFullscreen(); + pendingVsync = window->isVsyncEnabled(); + pendingResIndex = 0; + int curW = window->getWidth(); + int curH = window->getHeight(); + for (int i = 0; i < kResCount; i++) { + if (kResolutions[i][0] == curW && kResolutions[i][1] == curH) { + pendingResIndex = i; + break; + } + } + settingsInit = true; + } + + ImGuiIO& io = ImGui::GetIO(); + float screenW = io.DisplaySize.x; + float screenH = io.DisplaySize.y; + ImVec2 size(360.0f, 240.0f); + ImVec2 pos((screenW - size.x) * 0.5f, (screenH - size.y) * 0.5f); + + ImGui::SetNextWindowPos(pos, ImGuiCond_Always); + ImGui::SetNextWindowSize(size, ImGuiCond_Always); + ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar; + + if (ImGui::Begin("##SettingsWindow", nullptr, flags)) { + ImGui::Text("Settings"); + ImGui::Separator(); + + ImGui::Text("Video"); + ImGui::Checkbox("Fullscreen", &pendingFullscreen); + ImGui::Checkbox("VSync", &pendingVsync); + + const char* resLabel = "Resolution"; + const char* resItems[kResCount]; + char resBuf[kResCount][16]; + for (int i = 0; i < kResCount; i++) { + snprintf(resBuf[i], sizeof(resBuf[i]), "%dx%d", kResolutions[i][0], kResolutions[i][1]); + resItems[i] = resBuf[i]; + } + ImGui::Combo(resLabel, &pendingResIndex, resItems, kResCount); + + ImGui::Spacing(); + if (ImGui::Button("Apply", ImVec2(-1, 0))) { + window->setVsync(pendingVsync); + window->setFullscreen(pendingFullscreen); + window->applyResolution(kResolutions[pendingResIndex][0], kResolutions[pendingResIndex][1]); + } + if (ImGui::Button("Close", ImVec2(-1, 0))) { + showSettingsWindow = false; + } + } + ImGui::End(); +} + }} // namespace wowee::ui