diff --git a/extern/aurora b/extern/aurora index 0c68e0b4e8..e3fd6b1900 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 0c68e0b4e804fe835d59bf6f8c81f1dac4a617b3 +Subproject commit e3fd6b19008e40ba3888099e3c4555c9958e1c21 diff --git a/include/d/d_map.h b/include/d/d_map.h index 1acc7e4519..1cddbf3944 100644 --- a/include/d/d_map.h +++ b/include/d/d_map.h @@ -157,6 +157,9 @@ public: int getDispType() const; void _move(f32, f32, int, f32); void _draw(); +#if TARGET_PC + bool refreshTextureSize(); +#endif virtual ~dMap_c() { #if DEBUG diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 36269e87fd..3496a4b474 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -134,6 +134,9 @@ struct UserSettings { ConfigVar enableFpsOverlay; ConfigVar fpsOverlayCorner; ConfigVar maxFrameRate; + ConfigVar rememberWindowSize; + ConfigVar lastWindowWidth; + ConfigVar lastWindowHeight; } video; struct { diff --git a/src/d/actor/d_a_npc_ks.cpp b/src/d/actor/d_a_npc_ks.cpp index 71eeb16335..222827df63 100644 --- a/src/d/actor/d_a_npc_ks.cpp +++ b/src/d/actor/d_a_npc_ks.cpp @@ -6882,6 +6882,16 @@ static int daNpc_Ks_Delete(npc_ks_class* i_this) { i_this->model->stopZelAnime(); } +#if TARGET_PC + if (leader == i_this) { + leader = NULL; + } + + if (saru_p[i_this->set_id] == i_this) { + saru_p[i_this->set_id] = NULL; + } +#endif + return 1; } diff --git a/src/d/d_map.cpp b/src/d/d_map.cpp index 8cecead15a..765facc335 100644 --- a/src/d/d_map.cpp +++ b/src/d/d_map.cpp @@ -1213,6 +1213,10 @@ void dMap_c::changeTextureSize(int param_1, int param_2, int param_3) { JUT_ASSERT(2672, mImage_p != NULL); JUT_ASSERT(2673, mResTIMG != NULL); +#if TARGET_PC + GXDestroyCopyTex(mImage_p); +#endif + mTexSizeX = param_1 >> param_3; mTexSizeY = param_2 >> param_3; @@ -1226,6 +1230,24 @@ void dMap_c::changeTextureSize(int param_1, int param_2, int param_3) { } #endif +#if TARGET_PC +bool dMap_c::refreshTextureSize() { + JUT_ASSERT(2688, mImage_p != NULL); + JUT_ASSERT(2689, mResTIMG != NULL); + + const u16 oldWidth = mResTIMG->width; + const u16 oldHeight = mResTIMG->height; + makeResTIMG(mResTIMG, mTexSizeX, mTexSizeY, mImage_p, (u8*)m_res, 0x33); + + if (mResTIMG->width == oldWidth && mResTIMG->height == oldHeight) { + return false; + } + + GXDestroyCopyTex(mImage_p); + return true; +} +#endif + void dMap_c::_remove() { if (mImage_p != NULL) { #if TARGET_PC diff --git a/src/d/d_map_path.cpp b/src/d/d_map_path.cpp index a7579ee92d..cafbb93e38 100644 --- a/src/d/d_map_path.cpp +++ b/src/d/d_map_path.cpp @@ -15,32 +15,49 @@ #include #ifdef TARGET_PC -#include -#include -#include +#include "dusk/settings.h" +#include "m_Do/m_Do_graphic.h" +#include +#include -constexpr u16 kPreferredMapResolutionMultiplier = 4; -constexpr u32 kMaxMapRenderPixels = 4096 * 4096; -constexpr u16 kMapImageSide = 16 * kPreferredMapResolutionMultiplier; +#include +#include +#include +#include +#include +#include +#include + +constexpr u16 kMapIconResolutionMultiplier = 4; +constexpr u16 kMapImageSide = 16 * kMapIconResolutionMultiplier; constexpr u32 kMapImageTotalPixels = kMapImageSide * kMapImageSide; typedef std::function PaintI8Fn; -u16 map_resolution_multiplier(u16 width, u16 height) { - const u32 basePixels = static_cast(width) * height; - if (basePixels == 0) { - return 1; +u16 scaled_map_axis(u16 value, f32 scale) { + const auto scaledValue = + static_cast(std::max(1.0f, std::round(static_cast(value) * scale))); + return static_cast(std::min(scaledValue, std::numeric_limits::max())); +} + +aurora::Vec2 map_render_size_for(u16 width, u16 height) { + if (width == 0 || height == 0) { + return {width, height}; } - u16 scale = kPreferredMapResolutionMultiplier; - while (scale > 1) { - const u32 scalePixels = static_cast(scale) * scale; - if (basePixels <= kMaxMapRenderPixels / scalePixels) { - break; - } - scale--; - } - return scale; + u32 renderWidth = 0; + u32 renderHeight = 0; + AuroraGetRenderSize(&renderWidth, &renderHeight); + + const f32 logicalWidth = std::max(mDoGph_gInf_c::getWidthF(), 1.0f); + const f32 logicalHeight = std::max(mDoGph_gInf_c::getHeightF(), 1.0f); + const f32 irScaleX = renderWidth > 0 ? static_cast(renderWidth) / logicalWidth : 1.0f; + const f32 irScaleY = renderHeight > 0 ? static_cast(renderHeight) / logicalHeight : 1.0f; + const f32 hudScale = std::clamp(dusk::getSettings().game.hudScale.getValue(), 0.5f, 2.0f); + return { + scaled_map_axis(width, irScaleX * hudScale), + scaled_map_axis(height, irScaleY * hudScale), + }; } void paint_i8(std::span dst, size_t width, PaintI8Fn paint) { @@ -496,9 +513,9 @@ void dRenderingMap_c::makeResTIMG(ResTIMG* p_image, u16 width, u16 height, u8* p p_image->format = GX_TF_C8; p_image->alphaEnabled = 2; #ifdef TARGET_PC - const u16 scale = map_resolution_multiplier(width, height); - p_image->width = width * scale; - p_image->height = height * scale; + const auto [rw, rh] = map_render_size_for(width, height); + p_image->width = rw; + p_image->height = rh; #else p_image->width = width; p_image->height = height; @@ -581,16 +598,14 @@ void dRenderingFDAmap_c::drawBack() const { void dRenderingFDAmap_c::preRenderingMap() { #ifdef TARGET_PC - const u16 scale = map_resolution_multiplier(mTexWidth, mTexHeight); - const u16 w = mTexWidth * scale; - const u16 h = mTexHeight * scale; - GXCreateFrameBuffer(w, h); + const auto [rw, rh] = map_render_size_for(mTexWidth, mTexHeight); + GXCreateFrameBuffer(rw, rh); // Set logical viewport dimensions GXSetViewport(0.0f, 0.0f, mTexWidth, mTexHeight, 0.0f, 1.0f); GXSetScissor(0, 0, mTexWidth, mTexHeight); // Set render viewport dimensions - GXSetViewportRender(0.0f, 0.0f, w, h, 0.0f, 1.0f); - GXSetScissorRender(0, 0, w, h); + GXSetViewportRender(0.0f, 0.0f, rw, rh, 0.0f, 1.0f); + GXSetScissorRender(0, 0, rw, rh); #else GXSetViewport(0.0f, 0.0f, mTexWidth, mTexHeight, 0.0f, 1.0f); GXSetScissor(0, 0, mTexWidth, mTexHeight); @@ -628,11 +643,9 @@ void dRenderingFDAmap_c::preRenderingMap() { void dRenderingFDAmap_c::postRenderingMap() { GXSetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL); #ifdef TARGET_PC - const u16 scale = map_resolution_multiplier(mTexWidth, mTexHeight); - const u16 w = mTexWidth * scale; - const u16 h = mTexHeight * scale; - GXSetTexCopySrc(0, 0, w, h); - GXSetTexCopyDst(w, h, GX_CTF_R8, GX_FALSE); + const auto [rw, rh] = map_render_size_for(mTexWidth, mTexHeight); + GXSetTexCopySrc(0, 0, rw, rh); + GXSetTexCopyDst(rw, rh, GX_CTF_R8, GX_FALSE); GXCopyTex(field_0x4, GX_TRUE); GXRestoreFrameBuffer(); #else diff --git a/src/d/d_meter_map.cpp b/src/d/d_meter_map.cpp index c03214b963..95cd82cd53 100644 --- a/src/d/d_meter_map.cpp +++ b/src/d/d_meter_map.cpp @@ -539,6 +539,12 @@ void dMeterMap_c::_move(u32 param_0) { } #endif +#if TARGET_PC + if (mMap->refreshTextureSize()) { + mMapJ2DPicture->changeTexture(mMap->getResTIMGPointer(), 0); + } +#endif + int stayNo = dComIfGp_roomControl_getStayNo(); field_0x14 = param_0; diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 0422c6fcba..ee73dae360 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -11,6 +11,9 @@ UserSettings g_userSettings = { .enableFpsOverlay {"game.enableFpsOverlay", false}, .fpsOverlayCorner {"game.fpsOverlayCorner", 0}, .maxFrameRate {"video.maxFrameRate", 240}, + .rememberWindowSize {"video.rememberWindowSize", false}, + .lastWindowWidth {"video.lastWindowWidth", 0}, + .lastWindowHeight {"video.lastWindowHeight", 0}, }, .audio = { @@ -206,6 +209,9 @@ void registerSettings() { Register(g_userSettings.video.enableFpsOverlay); Register(g_userSettings.video.fpsOverlayCorner); Register(g_userSettings.video.maxFrameRate); + Register(g_userSettings.video.rememberWindowSize); + Register(g_userSettings.video.lastWindowWidth); + Register(g_userSettings.video.lastWindowHeight); // Audio Register(g_userSettings.audio.masterVolume); diff --git a/src/dusk/ui/overlay.cpp b/src/dusk/ui/overlay.cpp index 69c262720e..d6f87b9262 100644 --- a/src/dusk/ui/overlay.cpp +++ b/src/dusk/ui/overlay.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -187,43 +188,6 @@ void remove_element(Rml::Element*& elem) noexcept { } // namespace -// https://vplesko.com/posts/how_to_implement_an_fps_counter.html -void Overlay::advance_fps_counter(float& outFps, Uint64 perfFreq) { - if (perfFreq == 0) { - outFps = 0.f; - return; - } - - const Uint64 curr = SDL_GetPerformanceCounter(); - if (!mFpsHavePrevCounter) { - mFpsPrevCounter = curr; - mFpsHavePrevCounter = true; - outFps = 0.f; - return; - } - - const Uint64 processingTicks = curr - mFpsPrevCounter; - mFpsPrevCounter = curr; - - mFpsFrameEvents.push_back({curr, processingTicks}); - mFpsSumTicks += processingTicks; - - while (!mFpsFrameEvents.empty() && mFpsFrameEvents.front().endCounter + perfFreq < curr) { - mFpsSumTicks -= mFpsFrameEvents.front().processingTicks; - mFpsFrameEvents.pop_front(); - } - - const auto n = mFpsFrameEvents.size(); - if (n == 0 || mFpsSumTicks == 0) { - outFps = 0.f; - return; - } - - const double avgSeconds = - static_cast(mFpsSumTicks) / static_cast(n) / static_cast(perfFreq); - outFps = static_cast(1.0 / avgSeconds); -} - static std::string FormatTime(OSTime ticks) { OSCalendarTime t; OSTicksToCalendarTime(ticks, &t); @@ -276,8 +240,7 @@ void Overlay::update() { mFpsCounter->SetAttribute("corner", kFpsCorners[idx]); const Uint64 perfFreq = SDL_GetPerformanceFrequency(); - float fps = 0.f; - advance_fps_counter(fps, perfFreq); + float fps = aurora_get_fps(); const Uint64 now = SDL_GetPerformanceCounter(); // Limit updates to twice per second @@ -290,9 +253,6 @@ void Overlay::update() { } } else { mFpsCounter->RemoveAttribute("open"); - mFpsFrameEvents.clear(); - mFpsSumTicks = 0; - mFpsHavePrevCounter = false; mFpsLastUpdate = 0; } } diff --git a/src/dusk/ui/overlay.hpp b/src/dusk/ui/overlay.hpp index 8a2edd4a26..a8ccde5b9d 100644 --- a/src/dusk/ui/overlay.hpp +++ b/src/dusk/ui/overlay.hpp @@ -3,7 +3,6 @@ #include "document.hpp" #include -#include namespace dusk::ui { @@ -26,19 +25,7 @@ protected: Rml::Element* mSpeedrunIgt = nullptr; clock::time_point mCurrentToastStartTime; clock::time_point mMenuNotificationStartTime; - - struct FpsFrameEvent { - Uint64 endCounter; - Uint64 processingTicks; - }; - - std::deque mFpsFrameEvents; - Uint64 mFpsSumTicks = 0; - bool mFpsHavePrevCounter = false; - Uint64 mFpsPrevCounter = 0; Uint64 mFpsLastUpdate = 0; - - void advance_fps_counter(float& outFps, Uint64 perfFreq); }; } // namespace dusk::ui diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index c0f1dc235a..49757aab20 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -802,6 +802,21 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { pane.add_rml( "
Display the current framerate in a corner of the screen while playing."); }); + config_bool_select(leftPane, rightPane, getSettings().video.rememberWindowSize, + { + .key = "Remember Window Size", + .helpText = "Save and restore the previous session's window size when opening Dusklight.", + .onChange = + [](bool value) { + if (value && !dusk::getSettings().video.enableFullscreen) { + const auto windowSize = aurora::window::get_window_size(); + dusk::getSettings().video.lastWindowWidth.setValue(windowSize.width); + dusk::getSettings().video.lastWindowHeight.setValue(windowSize.height); + dusk::config::Save(); + } + }, + .isDisabled = [] { return IsMobile; }, + }); leftPane.add_section("Resolution"); graphics_tuner_control(*this, leftPane, rightPane, getSettings().game.internalResolutionScale, diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 7aba24693d..a65f355c69 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -265,6 +265,13 @@ void main01(void) { dusk::ui::handle_event(event->sdl); dusk::g_imguiConsole.HandleSDLEvent(event->sdl); break; + case AURORA_WINDOW_RESIZED: + if (dusk::getSettings().video.rememberWindowSize && !dusk::getSettings().video.enableFullscreen) { + dusk::getSettings().video.lastWindowWidth.setValue(event->windowSize.width); + dusk::getSettings().video.lastWindowHeight.setValue(event->windowSize.height); + dusk::config::Save(); + } + break; case AURORA_DISPLAY_SCALE_CHANGED: dusk::ImGuiEngine_Initialize(event->windowSize.scale); break; @@ -601,8 +608,18 @@ int game_main(int argc, char* argv[]) { config.startFullscreen = dusk::getSettings().video.enableFullscreen; config.windowPosX = -1; config.windowPosY = -1; - config.windowWidth = defaultWindowWidth * 2; - config.windowHeight = defaultWindowHeight * 2; + + const int lastWindowWidth = dusk::getSettings().video.lastWindowWidth.getValue(); + const int lastWindowHeight = dusk::getSettings().video.lastWindowHeight.getValue(); + + if (dusk::getSettings().video.rememberWindowSize && lastWindowWidth > 0 && lastWindowHeight > 0) { + config.windowWidth = lastWindowWidth; + config.windowHeight = lastWindowHeight; + } else { + config.windowWidth = defaultWindowWidth * 2; + config.windowHeight = defaultWindowHeight * 2; + } + config.desiredBackend = ResolveDesiredBackend(parsed_arg_options); config.logCallback = &aurora_log_callback; config.logLevel = startupLogLevel;