Compare commits

..

40 Commits

Author SHA1 Message Date
Hyper d696524dbf Rename UI Scale Mode to UI Alignment Mode 2025-02-08 12:09:15 +00:00
Skyth (Asilkan) e3ac47a797 Fix werehog HUD guide not having correct position at 4:3. (#311) 2025-02-08 14:16:33 +03:00
Hyper 72640c8749 options_menu: reset auto-scroll timer after manual scroll and retain last stick direction 2025-02-08 10:08:08 +00:00
Hyper 1687c65be9 Update resources submodule 2025-02-08 10:01:54 +00:00
Hyper 6dac017d00 Fix mission UI not extending for centred scale mode (#309) 2025-02-07 23:12:58 +00:00
Hyper 2150faed2e game_window: fix mouse cursor flickering after controller input 2025-02-07 20:42:02 +00:00
Hyper 2f1b98c570 game_window: revert window resize fix
This partially reverts commit 70ebdaa685.
2025-02-07 20:31:41 +00:00
Hyper 70ebdaa685 game_window: don't allow resizing until after boot, fix monitor switching 2025-02-07 20:28:57 +00:00
Hyper e1edd5f35d Fix Tornado Defense boss firing missiles too frequently (#306)
Co-authored-by: Skyth (Asilkan) <19259897+blueskythlikesclouds@users.noreply.github.com>
Co-authored-by: Darío <538504+DarioSamo@users.noreply.github.com>
2025-02-07 20:11:25 +00:00
Hyper 88df0e08b7 config_locale: update localisation
Co-Authored-By: Michael <15317421+ActualMandM@users.noreply.github.com>
2025-02-07 13:41:13 +00:00
Hyper 511c670def options_menu: fix inconsistent info scrolling delay 2025-02-07 10:59:44 +00:00
Hyper 16c35b45c2 options_menu: fix info scrolling not resetting if text is too small 2025-02-07 10:46:34 +00:00
Darío b291bdba91 Cherry-pick text changes from thumbnails branch. (#301)
* Cherry-pick text changes from thumbnails branch.

Co-authored-by: RadiantDerg <9061202+RadiantDerg@users.noreply.github.com>

* config_locale: update Aspect Ratio locale

Co-Authored-By: Michael <15317421+ActualMandM@users.noreply.github.com>

---------

Co-authored-by: RadiantDerg <9061202+RadiantDerg@users.noreply.github.com>
Co-authored-by: Hyper <34012267+hyperbx@users.noreply.github.com>
Co-authored-by: Michael <15317421+ActualMandM@users.noreply.github.com>
2025-02-07 10:45:01 +00:00
Hyper 727be2b47c Update resources submodule 2025-02-07 10:35:11 +00:00
Hyper 62ad3a1a13 achievement_manager: added UnlockAll method
Because I'm tired of writing this every time I need to debug unlocking achievements.
2025-02-07 10:30:03 +00:00
Darío 6c8dbdb6bc Check for closing during AchievementOverlay::Open (#302) 2025-02-07 10:23:10 +00:00
Hyper 71bb081645 game_window: respect per-monitor DPI scale
Co-Authored-By: Darío <538504+DarioSamo@users.noreply.github.com>
2025-02-07 10:11:06 +00:00
Hyper 871515b3be options_menu: start monitor index from 1 2025-02-07 09:58:39 +00:00
Darío 266d436c28 Block exit button from terminating the installer while it's in progress. (#300)
* Block exit button from terminating the installer while it's in progress.

* Fix quit prompt not appearing when closing the game from the taskbar.

---------

Co-authored-by: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com>
2025-02-07 01:21:18 +03:00
Darío e7cc5a858e Change progress bar animation on installer. (#299) 2025-02-07 00:38:18 +03:00
Skyth (Asilkan) 9549ba54aa Implement black bar drawing for loading and cutscenes. (#298) 2025-02-07 00:30:08 +03:00
Hyper 47b1f20679 message_window: added selection changed anim to options 2025-02-06 17:19:03 +00:00
Darío ef51f04d4f Add back button functionality to the installer. (#279)
* Add back button functionality to the installer.

* Nuclear exits.

* Adjust error code.

* Rework waiting time into the installer process instead.

* Extra waiting time during quitting.

* Restore button max widths.

* button_guide: set up Esc key texture

* Update installer_wizard.cpp

* Update resources submodule

* installer_wizard: decrease nav button margin

---------

Co-authored-by: Hyper <34012267+hyperbx@users.noreply.github.com>
2025-02-05 22:36:30 +03:00
Hyper b68dbec612 Update resources submodule 2025-02-05 17:25:41 +00:00
Skyth (Asilkan) 96108e1759 Use a separate upload buffer allocator for the main thread. (#281) 2025-02-05 17:02:27 +03:00
Hyper d3589979e4 imgui_utils: update selection textures 2025-02-05 11:45:49 +00:00
Darío 2db4a9c78c Expand on the text for the installer tutorials (#272)
* Expand on the text for the installer tutorials.

* Make both descriptions share the same paragraph.

* Update locale.cpp

Co-Authored-By: Goalringmod27 <88973067+Goalringmod27@users.noreply.github.com>

---------

Co-authored-by: Hyper <34012267+hyperbx@users.noreply.github.com>
Co-authored-by: Goalringmod27 <88973067+Goalringmod27@users.noreply.github.com>
2025-02-05 11:13:22 +00:00
Skyth 2d56566924 Remove the yield from the render thread. 2025-02-05 12:59:42 +03:00
Hyper 553e011dad CTitleStateMenu_patches: reset achievements on New Game (#278) 2025-02-05 12:19:18 +03:00
Darío 900ba7c916 Simplify required space text. (#280) 2025-02-05 02:47:31 +03:00
Hyper 66648d550a Implemented vertical scrolling for descriptions (#271)
* options_menu: implemented vertical scrolling for descriptions

* use correct size calculation

* remove empty lines from descriptions without value desc, move fix

* remove calculating the space for the next annotation after the last line

---------

Co-authored-by: DeaTh-G <hatvongeorge@gmail.com>
Co-authored-by: DeaTh-G <55578911+DeaTh-G@users.noreply.github.com>
2025-02-04 17:30:42 +00:00
Hyper c40ffbc70d Implemented fast scrolling on up/down hold for options menu (#275) 2025-02-04 15:29:22 +00:00
Skyth (Asilkan) ee97736d58 Make custom UI a bit more accurate looking. (#274)
* Update spacing for default font & pixel snap 2D primitives.

* Replicate the missing info outline from world map.
2025-02-04 14:53:43 +03:00
Skyth bbb3ebc25d Remove Win32 implementation of SetThreadIdealProcessor. 2025-02-04 12:41:19 +03:00
Hyper 52558a674e installer_wizard: fix source button text and alpha 2025-02-03 22:05:41 +00:00
Skyth (Asilkan) 11d0fd2f9c Implement rasterization path for framebuffer copy operations. (#270)
* Move all copies & resolves to rasterization.

* Fix Vulkan crash.

* Implement hardware resolve path for both color and depth targets.
2025-02-03 23:02:47 +03:00
Skyth (Asilkan) aaad10d797 Implement copy bypass optimization. (#262)
* Initial work on copy bypass optimization.

* Force depth stencil textures to be transient.

* Get rid of texture copying for shadow maps.

* Move barrier populate function.

* Set viewport/scissor rect explicitly for MSAA depth resolve.
2025-02-02 21:29:47 +03:00
Skyth (Asilkan) 342d696f99 Implement vertical marquee fade. (#261) 2025-02-02 20:09:19 +03:00
Hyper 0426b79094 config: update key bindings enum template 2025-02-02 15:51:16 +00:00
Hyper 3497d9b34b CTitleStateIntro_patches: fixed message inconsistencies (#259) 2025-02-01 13:37:48 +00:00
70 changed files with 2114 additions and 727 deletions
+16 -9
View File
@@ -149,7 +149,8 @@ set(UNLEASHED_RECOMP_PATCHES_CXX_SOURCES
set(UNLEASHED_RECOMP_UI_CXX_SOURCES
"ui/achievement_menu.cpp"
"ui/achievement_overlay.cpp"
"ui/achievement_overlay.cpp"
"ui/black_bar.cpp"
"ui/button_guide.cpp"
"ui/fader.cpp"
"ui/game_window.cpp"
@@ -350,10 +351,12 @@ file(CHMOD ${DIRECTX_DXC_TOOL} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
if (WIN32)
target_link_libraries(UnleashedRecomp PRIVATE
comctl32
ntdll
winmm
comctl32
dwmapi
ntdll
Shcore
Synchronization
winmm
)
endif()
@@ -414,7 +417,9 @@ function(compile_pixel_shader FILE_PATH)
endfunction()
compile_pixel_shader(blend_color_alpha_ps)
compile_vertex_shader(copy_vs)
compile_vertex_shader(copy_vs)
compile_pixel_shader(copy_color_ps)
compile_pixel_shader(copy_depth_ps)
compile_pixel_shader(csd_filter_ps)
compile_vertex_shader(csd_no_tex_vs)
compile_vertex_shader(csd_vs)
@@ -427,7 +432,10 @@ compile_pixel_shader(gamma_correction_ps)
compile_pixel_shader(imgui_ps)
compile_vertex_shader(imgui_vs)
compile_pixel_shader(movie_ps)
compile_vertex_shader(movie_vs)
compile_vertex_shader(movie_vs)
compile_pixel_shader(resolve_msaa_color_2x)
compile_pixel_shader(resolve_msaa_color_4x)
compile_pixel_shader(resolve_msaa_color_8x)
compile_pixel_shader(resolve_msaa_depth_2x)
compile_pixel_shader(resolve_msaa_depth_4x)
compile_pixel_shader(resolve_msaa_depth_8x)
@@ -472,8 +480,7 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/co
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/general_window.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/general_window.dds" ARRAY_NAME "g_general_window" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/hedge-dev.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/hedge-dev.dds" ARRAY_NAME "g_hedgedev" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/kbm.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/kbm.dds" ARRAY_NAME "g_kbm" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select_fade.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select_fade.dds" ARRAY_NAME "g_select_fade" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select_fill.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select_fill.dds" ARRAY_NAME "g_select_fill" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select.dds" ARRAY_NAME "g_select" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/light.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/light.dds" ARRAY_NAME "g_light" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/arrow_circle.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/arrow_circle.dds" ARRAY_NAME "g_arrow_circle" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_001.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_001.dds" ARRAY_NAME "g_install_001" COMPRESSION_TYPE "zstd")
@@ -523,7 +530,7 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/op
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_of_day_transition_playstation.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_of_day_transition_playstation.dds" ARRAY_NAME "g_time_of_day_transition_playstation" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/transparency_antialiasing_false.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/transparency_antialiasing_false.dds" ARRAY_NAME "g_transparency_antialiasing_false" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/transparency_antialiasing_true.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/transparency_antialiasing_true.dds" ARRAY_NAME "g_transparency_antialiasing_true" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_scale_mode.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_scale_mode.dds" ARRAY_NAME "g_ui_scale_mode" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_alignment_mode.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_alignment_mode.dds" ARRAY_NAME "g_ui_alignment_mode" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vertical_camera.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vertical_camera.dds" ARRAY_NAME "g_vertical_camera" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/voice_language.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/voice_language.dds" ARRAY_NAME "g_voice_language" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vibration.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration.dds" ARRAY_NAME "g_vibration" COMPRESSION_TYPE "zstd")
+6
View File
@@ -62,6 +62,10 @@
#include "SWA/Camera/Camera.h"
#include "SWA/Camera/CameraController.h"
#include "SWA/CharacterUtility/CharacterProxy.h"
#include "SWA/ExtraStage/Tails/Enemy/Boss/ExStageBoss.h"
#include "SWA/ExtraStage/Tails/Enemy/Boss/State/StateBase.h"
#include "SWA/ExtraStage/Tails/Enemy/Boss/State/StateBattle.h"
#include "SWA/ExtraStage/Tails/Player/ExPlayerTails.h"
#include "SWA/Globals.h"
#include "SWA/HUD/GeneralWindow/GeneralWindow.h"
#include "SWA/HUD/Loading/Loading.h"
@@ -80,6 +84,7 @@
#include "SWA/Menu/MenuWindowBase.h"
#include "SWA/Movie/MovieDisplayer.h"
#include "SWA/Movie/MovieManager.h"
#include "SWA/Object/Common/DashPanel/ObjDashPanel.h"
#include "SWA/Player/Character/EvilSonic/EvilSonic.h"
#include "SWA/Player/Character/EvilSonic/EvilSonicContext.h"
#include "SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h"
@@ -102,6 +107,7 @@
#include "SWA/System/GameMode/Title/TitleMenu.h"
#include "SWA/System/GameMode/Title/TitleStateBase.h"
#include "SWA/System/GameMode/Title/TitleStateIntro.h"
#include "SWA/System/GameMode/Title/TitleStateMenu.h"
#include "SWA/System/GameMode/Title/TitleStateWorldMap.h"
#include "SWA/System/GameMode/WorldMap/WorldMapCamera.h"
#include "SWA/System/GameMode/WorldMap/WorldMapCursor.h"
@@ -0,0 +1,36 @@
#pragma once
#include <SWA.inl>
namespace SWA
{
class CExStageBoss
{
public:
class CStateBase;
class CStateBattle;
class CExStageBossStateContext
{
public:
SWA_INSERT_PADDING(0x14C);
be<float> m_SplineProgress;
SWA_INSERT_PADDING(0x0C);
be<float> m_SplineSpeed;
SWA_INSERT_PADDING(0x28);
be<float> m_Field188;
be<float> m_Field18C;
SWA_INSERT_PADDING(0x21);
bool m_IsBattleStart;
SWA_INSERT_PADDING(0x36E);
be<float> m_Field520;
};
};
SWA_ASSERT_OFFSETOF(CExStageBoss::CExStageBossStateContext, m_SplineProgress, 0x14C);
SWA_ASSERT_OFFSETOF(CExStageBoss::CExStageBossStateContext, m_SplineSpeed, 0x15C);
SWA_ASSERT_OFFSETOF(CExStageBoss::CExStageBossStateContext, m_Field188, 0x188);
SWA_ASSERT_OFFSETOF(CExStageBoss::CExStageBossStateContext, m_Field18C, 0x18C);
SWA_ASSERT_OFFSETOF(CExStageBoss::CExStageBossStateContext, m_IsBattleStart, 0x1B1);
SWA_ASSERT_OFFSETOF(CExStageBoss::CExStageBossStateContext, m_Field520, 0x520);
}
@@ -0,0 +1,9 @@
#pragma once
#include <SWA.inl>
#include "SWA/ExtraStage/Tails/Enemy/Boss/ExStageBoss.h"
namespace SWA
{
class CExStageBoss::CStateBase : public Hedgehog::Universe::CStateMachineBase::CStateBase {};
}
@@ -0,0 +1,18 @@
#pragma once
#include <SWA.inl>
#include "SWA/ExtraStage/Tails/Enemy/Boss/ExStageBoss.h"
namespace SWA
{
class CExStageBoss::CStateBattle : public CExStageBoss::CStateBase
{
public:
SWA_INSERT_PADDING(0x08);
be<float> m_Field68;
be<float> m_FramesSinceLastMissile;
};
SWA_ASSERT_OFFSETOF(CExStageBoss::CStateBattle, m_Field68, 0x68);
SWA_ASSERT_OFFSETOF(CExStageBoss::CStateBattle, m_FramesSinceLastMissile, 0x6C);
}
@@ -0,0 +1,35 @@
#pragma once
#include <SWA.inl>
namespace SWA
{
class CExPlayerTails
{
public:
class CExPlayerTailsStateContext
{
public:
SWA_INSERT_PADDING(0x1F8);
be<float> m_SplineBossStart;
be<float> m_SplineEnd;
SWA_INSERT_PADDING(0x30);
be<float> m_SplineProgress;
SWA_INSERT_PADDING(0x10);
xpointer<void> m_Field244;
SWA_INSERT_PADDING(0x18);
be<float> m_SplineSpeed;
SWA_INSERT_PADDING(0x0C);
be<uint32_t> m_State; // 0 - Intro; 1 - Boss Intro; 3 - Boss
};
class CStateBase : public Hedgehog::Universe::CStateMachineBase::CStateBase {};
};
SWA_ASSERT_OFFSETOF(CExPlayerTails::CExPlayerTailsStateContext, m_SplineBossStart, 0x1F8);
SWA_ASSERT_OFFSETOF(CExPlayerTails::CExPlayerTailsStateContext, m_SplineEnd, 0x1FC);
SWA_ASSERT_OFFSETOF(CExPlayerTails::CExPlayerTailsStateContext, m_SplineProgress, 0x230);
SWA_ASSERT_OFFSETOF(CExPlayerTails::CExPlayerTailsStateContext, m_Field244, 0x244);
SWA_ASSERT_OFFSETOF(CExPlayerTails::CExPlayerTailsStateContext, m_SplineSpeed, 0x260);
SWA_ASSERT_OFFSETOF(CExPlayerTails::CExPlayerTailsStateContext, m_State, 0x270);
}
@@ -4,6 +4,15 @@
namespace SWA
{
enum EWindowStatus : uint32_t
{
eWindowStatus_Closed,
eWindowStatus_OpeningMessage = 2,
eWindowStatus_DisplayingMessage,
eWindowStatus_OpeningControls,
eWindowStatus_DisplayingControls
};
class CGeneralWindow
{
public:
@@ -14,5 +23,20 @@ namespace SWA
Chao::CSD::RCPtr<Chao::CSD::CScene> m_rcWindow_2;
Chao::CSD::RCPtr<Chao::CSD::CScene> m_rcWindowSelect;
Chao::CSD::RCPtr<Chao::CSD::CScene> m_rcFooter;
SWA_INSERT_PADDING(0x58);
be<EWindowStatus> m_Status;
be<uint32_t> m_CursorIndex;
SWA_INSERT_PADDING(0x04);
be<uint32_t> m_SelectedIndex;
};
SWA_ASSERT_OFFSETOF(CGeneralWindow, m_rcGeneral, 0xD0);
SWA_ASSERT_OFFSETOF(CGeneralWindow, m_rcBg, 0xD8);
SWA_ASSERT_OFFSETOF(CGeneralWindow, m_rcWindow, 0xE0);
SWA_ASSERT_OFFSETOF(CGeneralWindow, m_rcWindow_2, 0xE8);
SWA_ASSERT_OFFSETOF(CGeneralWindow, m_rcWindowSelect, 0xF0);
SWA_ASSERT_OFFSETOF(CGeneralWindow, m_rcFooter, 0xF8);
SWA_ASSERT_OFFSETOF(CGeneralWindow, m_Status, 0x158);
SWA_ASSERT_OFFSETOF(CGeneralWindow, m_CursorIndex, 0x15C);
SWA_ASSERT_OFFSETOF(CGeneralWindow, m_SelectedIndex, 0x164);
}
@@ -0,0 +1,14 @@
#pragma once
#include <SWA.inl>
namespace SWA
{
class CObjDashPanel
{
public:
SWA_INSERT_PADDING(0xE8);
be<float> m_FieldE8;
be<float> m_Speed;
};
}
@@ -34,7 +34,9 @@ namespace SWA
SWA_INSERT_PADDING(0x88);
Hedgehog::Base::CSharedString m_StageName;
xpointer<CSoundAdministrator> m_pSoundAdministrator;
SWA_INSERT_PADDING(0x124);
SWA_INSERT_PADDING(0x48);
xpointer<CGeneralWindow> m_pGeneralWindow;
SWA_INSERT_PADDING(0xD8);
SScoreInfo m_ScoreInfo;
SWA_INSERT_PADDING(0x0C);
};
@@ -60,6 +62,7 @@ namespace SWA
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_spDatabase, 0x1C);
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_StageName, 0xAC);
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_pSoundAdministrator, 0xB0);
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_pGeneralWindow, 0xFC);
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_ScoreInfo, 0x1D8);
SWA_ASSERT_SIZEOF(CGameDocument::CMember, 0x230);
@@ -4,10 +4,36 @@
namespace SWA
{
class CTitleMenu
class CTitleMenu : public CMenuWindowBase
{
public:
SWA_INSERT_PADDING(0x44);
SWA_INSERT_PADDING(0x28);
be<uint32_t> m_Field38;
bool m_Field3C; // Seems to be related to exit transition.
SWA_INSERT_PADDING(0x04);
be<uint32_t> m_CursorIndex;
SWA_INSERT_PADDING(0x0C);
bool m_Field54; // Seems to be related to exit transition.
SWA_INSERT_PADDING(0x0B);
be<float> m_Field60;
SWA_INSERT_PADDING(0x34);
bool m_Field98;
bool m_IsDeleteCheckMessageOpen;
bool m_Field9A; // Seems to be related to cursor selection.
SWA_INSERT_PADDING(0x04);
bool m_Field9F;
SWA_INSERT_PADDING(0x02);
bool m_IsDLCInfoMessageOpen;
};
SWA_ASSERT_OFFSETOF(CTitleMenu, m_Field38, 0x38);
SWA_ASSERT_OFFSETOF(CTitleMenu, m_Field3C, 0x3C);
SWA_ASSERT_OFFSETOF(CTitleMenu, m_CursorIndex, 0x44);
SWA_ASSERT_OFFSETOF(CTitleMenu, m_Field54, 0x54);
SWA_ASSERT_OFFSETOF(CTitleMenu, m_Field60, 0x60);
SWA_ASSERT_OFFSETOF(CTitleMenu, m_Field98, 0x98);
SWA_ASSERT_OFFSETOF(CTitleMenu, m_IsDeleteCheckMessageOpen, 0x99);
SWA_ASSERT_OFFSETOF(CTitleMenu, m_Field9A, 0x9A);
SWA_ASSERT_OFFSETOF(CTitleMenu, m_Field9F, 0x9F);
SWA_ASSERT_OFFSETOF(CTitleMenu, m_IsDLCInfoMessageOpen, 0xA2);
}
@@ -0,0 +1,8 @@
#pragma once
#include <SWA.inl>
namespace SWA
{
class CTitleStateMenu : public CTitleStateBase {};
}
-4
View File
@@ -165,11 +165,7 @@ int GetThreadPriorityImpl(GuestThreadHandle* hThread)
uint32_t SetThreadIdealProcessorImpl(GuestThreadHandle* hThread, uint32_t dwIdealProcessor)
{
#ifdef _WIN32
return SetThreadIdealProcessor(hThread == GetKernelObject(CURRENT_THREAD_HANDLE) ? GetCurrentThread() : hThread->thread.native_handle(), dwIdealProcessor);
#else
return 0;
#endif
}
GUEST_FUNCTION_HOOK(sub_82DFA2E8, SetThreadNameImpl);
+11 -10
View File
@@ -1,15 +1,16 @@
#pragma once
#define IMGUI_SHADER_MODIFIER_NONE 0
#define IMGUI_SHADER_MODIFIER_SCANLINE 1
#define IMGUI_SHADER_MODIFIER_CHECKERBOARD 2
#define IMGUI_SHADER_MODIFIER_SCANLINE_BUTTON 3
#define IMGUI_SHADER_MODIFIER_TEXT_SKEW 4
#define IMGUI_SHADER_MODIFIER_MARQUEE_FADE 5
#define IMGUI_SHADER_MODIFIER_GRAYSCALE 6
#define IMGUI_SHADER_MODIFIER_TITLE_BEVEL 7
#define IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL 8
#define IMGUI_SHADER_MODIFIER_RECTANGLE_BEVEL 9
#define IMGUI_SHADER_MODIFIER_NONE 0
#define IMGUI_SHADER_MODIFIER_SCANLINE 1
#define IMGUI_SHADER_MODIFIER_CHECKERBOARD 2
#define IMGUI_SHADER_MODIFIER_SCANLINE_BUTTON 3
#define IMGUI_SHADER_MODIFIER_TEXT_SKEW 4
#define IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE 5
#define IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE 6
#define IMGUI_SHADER_MODIFIER_GRAYSCALE 7
#define IMGUI_SHADER_MODIFIER_TITLE_BEVEL 8
#define IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL 9
#define IMGUI_SHADER_MODIFIER_RECTANGLE_BEVEL 10
#ifdef __cplusplus
@@ -221,6 +221,8 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
for (size_t i = 0; i < atlas->ConfigData.size(); i++)
{
auto& config = atlas->ConfigData[i];
bool increaseSpacing = strstr(config.Name, "Seurat") != nullptr;
auto& [index, count] = ranges[i];
for (size_t j = 0; j < count; j++)
{
@@ -228,6 +230,11 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
double x0, y0, x1, y1, u0, v0, u1, v1;
glyph.getQuadPlaneBounds(x0, y0, x1, y1);
glyph.getQuadAtlasBounds(u0, v0, u1, v1);
double advance = glyph.getAdvance();
if (increaseSpacing && glyph.getCodepoint() == ' ')
advance *= 1.5;
config.DstFont->AddGlyph(
&config,
glyph.getCodepoint(),
@@ -239,7 +246,7 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
v1 / packer.height,
u1 / packer.width,
v0 / packer.height,
glyph.getAdvance());
advance);
}
config.DstFont->BuildLookupTable();
+22 -2
View File
@@ -27,6 +27,8 @@
//# define D3D12_DEBUG_LAYER_GPU_BASED_VALIDATION_ENABLED
#endif
//#define D3D12_DEBUG_SET_STABLE_POWER_STATE
// Old Windows SDK versions don't provide this macro, so we workaround it by making sure it is defined.
#ifndef D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE
#define D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE)
@@ -692,6 +694,20 @@ namespace plume {
);
}
static D3D12_RESOLVE_MODE toD3D12(RenderResolveMode resolveMode) {
switch (resolveMode) {
case RenderResolveMode::MIN:
return D3D12_RESOLVE_MODE_MIN;
case RenderResolveMode::MAX:
return D3D12_RESOLVE_MODE_MAX;
case RenderResolveMode::AVERAGE:
return D3D12_RESOLVE_MODE_AVERAGE;
default:
assert(false && "Unknown resolve mode.");
return D3D12_RESOLVE_MODE_AVERAGE;
}
}
static void setObjectName(ID3D12Object *object, const std::string &name) {
const std::wstring wideCharName = Utf8ToUtf16(name);
object->SetName(wideCharName.c_str());
@@ -1916,7 +1932,7 @@ namespace plume {
resetSamplePositions();
}
void D3D12CommandList::resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect) {
void D3D12CommandList::resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect, RenderResolveMode resolveMode) {
assert(dstTexture != nullptr);
assert(srcTexture != nullptr);
@@ -1931,7 +1947,7 @@ namespace plume {
}
setSamplePositions(interfaceDstTexture);
d3d->ResolveSubresourceRegion(interfaceDstTexture->d3d, 0, dstX, dstY, interfaceSrcTexture->d3d, 0, (srcRect != nullptr) ? &rect : nullptr, toDXGI(interfaceDstTexture->desc.format), D3D12_RESOLVE_MODE_AVERAGE);
d3d->ResolveSubresourceRegion(interfaceDstTexture->d3d, 0, dstX, dstY, interfaceSrcTexture->d3d, 0, (srcRect != nullptr) ? &rect : nullptr, toDXGI(interfaceDstTexture->desc.format), toD3D12(resolveMode));
resetSamplePositions();
}
@@ -3373,6 +3389,10 @@ namespace plume {
return;
}
#ifdef D3D12_DEBUG_SET_STABLE_POWER_STATE
d3d->SetStablePowerState(TRUE);
#endif
D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
allocatorDesc.pDevice = d3d;
allocatorDesc.pAdapter = adapter;
+1 -1
View File
@@ -192,7 +192,7 @@ namespace plume {
void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override;
void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override;
void resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override;
void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect) override;
void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect, RenderResolveMode resolveMode) override;
void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) override;
void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override;
void discardTexture(const RenderTexture* texture) override;
@@ -143,7 +143,7 @@ namespace plume {
virtual void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) = 0;
virtual void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) = 0;
virtual void resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) = 0;
virtual void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect = nullptr) = 0;
virtual void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect = nullptr, RenderResolveMode resolveMode = RenderResolveMode::AVERAGE) = 0;
virtual void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) = 0;
virtual void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) = 0;
virtual void discardTexture(const RenderTexture* texture) = 0; // D3D12 only.
@@ -483,6 +483,12 @@ namespace plume {
CPU
};
enum class RenderResolveMode {
MIN,
MAX,
AVERAGE
};
// Global functions.
constexpr uint32_t RenderFormatSize(RenderFormat format) {
+3 -2
View File
@@ -3074,12 +3074,13 @@ namespace plume {
}
void VulkanCommandList::resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) {
resolveTextureRegion(dstTexture, 0, 0, srcTexture, nullptr);
resolveTextureRegion(dstTexture, 0, 0, srcTexture, nullptr, RenderResolveMode::AVERAGE);
}
void VulkanCommandList::resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect) {
void VulkanCommandList::resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect, RenderResolveMode resolveMode) {
assert(dstTexture != nullptr);
assert(srcTexture != nullptr);
assert(resolveMode == RenderResolveMode::AVERAGE && "Vulkan only supports AVERAGE resolve mode.");
thread_local std::vector<VkImageResolve> imageResolves;
imageResolves.clear();
+1 -1
View File
@@ -315,7 +315,7 @@ namespace plume {
void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override;
void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override;
void resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override;
void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect) override;
void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect, RenderResolveMode resolveMode) override;
void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) override;
void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override;
void discardTexture(const RenderTexture* texture) override;
@@ -0,0 +1,8 @@
#include "copy_common.hlsli"
Texture2D<float4> g_Texture2DDescriptorHeap[] : register(t0, space0);
float4 main(in float4 position : SV_Position) : SV_Target
{
return g_Texture2DDescriptorHeap[g_PushConstants.ResourceDescriptorIndex].Load(int3(position.xy, 0));
}
@@ -0,0 +1,8 @@
#pragma once
struct PushConstants
{
uint ResourceDescriptorIndex;
};
[[vk::push_constant]] ConstantBuffer<PushConstants> g_PushConstants : register(b3, space4);
@@ -0,0 +1,8 @@
#include "copy_common.hlsli"
Texture2D<float> g_Texture2DDescriptorHeap[] : register(t0, space0);
float main(in float4 position : SV_Position) : SV_Depth
{
return g_Texture2DDescriptorHeap[g_PushConstants.ResourceDescriptorIndex].Load(int3(position.xy, 0));
}
+10 -2
View File
@@ -135,10 +135,18 @@ float4 main(in Interpolators interpolators) : SV_Target
}
}
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_MARQUEE_FADE)
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE)
{
float minAlpha = saturate((interpolators.Position.x - g_PushConstants.BoundsMin.x) / g_PushConstants.Scale.x);
float maxAlpha = saturate((g_PushConstants.BoundsMax.x - interpolators.Position.x) / g_PushConstants.Scale.x);
float maxAlpha = saturate((g_PushConstants.BoundsMax.x - interpolators.Position.x) / g_PushConstants.Scale.y);
color.a *= minAlpha;
color.a *= maxAlpha;
}
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE)
{
float minAlpha = saturate((interpolators.Position.y - g_PushConstants.BoundsMin.y) / g_PushConstants.Scale.x);
float maxAlpha = saturate((g_PushConstants.BoundsMax.y - interpolators.Position.y) / g_PushConstants.Scale.y);
color.a *= minAlpha;
color.a *= maxAlpha;
+2 -1
View File
@@ -7,7 +7,8 @@ void main(in float2 position : POSITION, in float2 uv : TEXCOORD, in float4 colo
if (position.y < g_PushConstants.Origin.y)
position.x += g_PushConstants.Scale.x;
}
else if (g_PushConstants.ShaderModifier != IMGUI_SHADER_MODIFIER_MARQUEE_FADE)
else if (g_PushConstants.ShaderModifier != IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE &&
g_PushConstants.ShaderModifier != IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE)
{
position.xy = g_PushConstants.Origin + (position.xy - g_PushConstants.Origin) * g_PushConstants.Scale;
}
@@ -0,0 +1,15 @@
#pragma once
#include "copy_common.hlsli"
Texture2DMS<float4, SAMPLE_COUNT> g_Texture2DMSDescriptorHeap[] : register(t0, space0);
float4 main(in float4 position : SV_Position) : SV_Target
{
float4 result = g_Texture2DMSDescriptorHeap[g_PushConstants.ResourceDescriptorIndex].Load(int2(position.xy), 0);
[unroll] for (int i = 1; i < SAMPLE_COUNT; i++)
result += g_Texture2DMSDescriptorHeap[g_PushConstants.ResourceDescriptorIndex].Load(int2(position.xy), i);
return result / SAMPLE_COUNT;
}
@@ -0,0 +1,2 @@
#define SAMPLE_COUNT 2
#include "resolve_msaa_color.hlsli"
@@ -0,0 +1,2 @@
#define SAMPLE_COUNT 4
#include "resolve_msaa_color.hlsli"
@@ -0,0 +1,2 @@
#define SAMPLE_COUNT 8
#include "resolve_msaa_color.hlsli"
@@ -1,11 +1,6 @@
#pragma once
struct PushConstants
{
uint ResourceDescriptorIndex;
};
[[vk::push_constant]] ConstantBuffer<PushConstants> g_PushConstants : register(b3, space4);
#include "copy_common.hlsli"
Texture2DMS<float, SAMPLE_COUNT> g_Texture2DMSDescriptorHeap[] : register(t0, space0);
File diff suppressed because it is too large Load Diff
+2
View File
@@ -158,6 +158,7 @@ struct GuestTexture : GuestBaseTexture
void* mappedMemory = nullptr;
std::unique_ptr<RenderFramebuffer> framebuffer;
std::unique_ptr<GuestTexture> patchedTexture;
struct GuestSurface* sourceSurface = nullptr;
};
struct GuestLockedRect
@@ -205,6 +206,7 @@ struct GuestSurface : GuestBaseTexture
uint32_t guestFormat = 0;
ankerl::unordered_dense::map<const RenderTexture*, std::unique_ptr<RenderFramebuffer>> framebuffers;
RenderSampleCounts sampleCount = RenderSampleCount::COUNT_1;
ankerl::unordered_dense::set<GuestTexture*> destinationTextures;
};
enum GuestDeclType
+10
View File
@@ -239,12 +239,16 @@ int HID_OnSDLEvent(void*, SDL_Event* event)
if (event->type == SDL_CONTROLLERAXISMOTION)
{
if (abs(event->caxis.value) > 8000)
{
SDL_ShowCursor(SDL_DISABLE);
SetControllerInputDevice(controller);
}
controller->PollAxis();
}
else
{
SDL_ShowCursor(SDL_DISABLE);
SetControllerInputDevice(controller);
controller->Poll();
@@ -261,8 +265,14 @@ int HID_OnSDLEvent(void*, SDL_Event* event)
case SDL_MOUSEMOTION:
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
if (!GameWindow::IsFullscreen() || GameWindow::s_isFullscreenCursorVisible)
SDL_ShowCursor(SDL_ENABLE);
hid::g_inputDevice = hid::EInputDevice::Mouse;
break;
}
case SDL_WINDOWEVENT:
{
+26 -5
View File
@@ -67,7 +67,7 @@ static std::unique_ptr<VirtualFileSystem> createFileSystemFromPath(const std::fi
}
}
static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, bool skipHashChecks, std::vector<uint8_t> &fileData, Journal &journal, const std::function<void()> &progressCallback) {
static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, bool skipHashChecks, std::vector<uint8_t> &fileData, Journal &journal, const std::function<bool()> &progressCallback) {
const std::string filename(pair.first);
const uint32_t hashCount = pair.second;
if (!sourceVfs.exists(filename))
@@ -139,7 +139,13 @@ static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFi
}
journal.progressCounter += fileData.size();
progressCallback();
if (!progressCallback())
{
journal.lastResult = Journal::Result::Cancelled;
journal.lastErrorMessage = "Installation was cancelled.";
return false;
}
return true;
}
@@ -266,7 +272,7 @@ bool Installer::computeTotalSize(std::span<const FilePair> filePairs, const uint
return true;
}
bool Installer::copyFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<void()> &progressCallback)
bool Installer::copyFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<bool()> &progressCallback)
{
std::error_code ec;
if (!std::filesystem::exists(targetDirectory) && !std::filesystem::create_directories(targetDirectory, ec))
@@ -429,7 +435,7 @@ bool Installer::parseSources(const Input &input, Journal &journal, Sources &sour
return true;
}
bool Installer::install(const Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, const std::function<void()> &progressCallback)
bool Installer::install(const Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, std::chrono::seconds endWaitTime, const std::function<bool()> &progressCallback)
{
// Install files in reverse order of importance. In case of a process crash or power outage, this will increase the likelihood of the installation
// missing critical files required for the game to run. These files are used as the way to detect if the game is installed.
@@ -497,7 +503,22 @@ bool Installer::install(const Sources &sources, const std::filesystem::path &tar
// Update the progress with the artificial amount attributed to the patching.
journal.progressCounter += PatcherContribution;
progressCallback();
for (uint32_t i = 0; i < 2; i++)
{
if (!progressCallback())
{
journal.lastResult = Journal::Result::Cancelled;
journal.lastErrorMessage = "Installation was cancelled.";
return false;
}
if (i == 0)
{
// Wait the specified amount of time to allow the consumer of the callbacks to animate, halt or cancel the installation for a while after it's finished.
std::this_thread::sleep_for(endWaitTime);
}
}
return true;
}
+3 -2
View File
@@ -22,6 +22,7 @@ struct Journal
enum class Result
{
Success,
Cancelled,
VirtualFileSystemFailed,
DirectoryCreationFailed,
FileMissing,
@@ -75,10 +76,10 @@ struct Installer
static bool checkDLCInstall(const std::filesystem::path &baseDirectory, DLC dlc);
static bool checkAllDLC(const std::filesystem::path &baseDirectory);
static bool computeTotalSize(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, Journal &journal, uint64_t &totalSize);
static bool copyFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<void()> &progressCallback);
static bool copyFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<bool()> &progressCallback);
static bool parseContent(const std::filesystem::path &sourcePath, std::unique_ptr<VirtualFileSystem> &targetVfs, Journal &journal);
static bool parseSources(const Input &input, Journal &journal, Sources &sources);
static bool install(const Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, const std::function<void()> &progressCallback);
static bool install(const Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, std::chrono::seconds endWaitTime, const std::function<bool()> &progressCallback);
static void rollback(Journal &journal);
// Convenience method for checking if the specified file contains the game. This should be used when the user selects the file.
+19 -19
View File
@@ -27,11 +27,11 @@
CONFIG_DEFINE_LOCALE(Language)
{
{ ELanguage::English, { "Language", "Change the language used for text and logos." } },
{ ELanguage::Japanese, { "言語", "[PLACEHOLDER]" } },
{ ELanguage::German, { "Sprache", "[PLACEHOLDER]" } },
{ ELanguage::French, { "Langue", "[PLACEHOLDER]" } },
{ ELanguage::Spanish, { "Idioma", "[PLACEHOLDER]" } },
{ ELanguage::Italian, { "Lingua", "[PLACEHOLDER]" } }
{ ELanguage::Japanese, { "言語", "" } },
{ ELanguage::German, { "Sprache", "" } },
{ ELanguage::French, { "Langue", "" } },
{ ELanguage::Spanish, { "Idioma", "" } },
{ ELanguage::Italian, { "Lingua", "" } }
};
CONFIG_DEFINE_ENUM_LOCALE(ELanguage)
@@ -196,7 +196,7 @@ CONFIG_DEFINE_LOCALE(MusicAttenuation)
CONFIG_DEFINE_LOCALE(ChannelConfiguration)
{
{ ELanguage::English, { "Channel Configuration", "" } }
{ ELanguage::English, { "Channel Configuration", "Change the output mode for your playback device." } }
};
CONFIG_DEFINE_ENUM_LOCALE(EChannelConfiguration)
@@ -246,7 +246,9 @@ CONFIG_DEFINE_ENUM_LOCALE(EAspectRatio)
ELanguage::English,
{
{ EAspectRatio::Auto, { "AUTO", "Auto: the aspect ratio will dynamically adjust to the window size." } },
{ EAspectRatio::OriginalNarrow, { "ORIGINAL 4:3", "" } }
{ EAspectRatio::Wide, { "16:9", "16:9: locks the game to a widescreen aspect ratio." } },
{ EAspectRatio::Narrow, { "4:3", "4:3: locks the game to a narrow aspect ratio." } },
{ EAspectRatio::OriginalNarrow, { "ORIGINAL 4:3", "Original 4:3: locks the game to a narrow aspect ratio and retains parity with the game's original implementation." } }
}
}
};
@@ -273,7 +275,7 @@ CONFIG_DEFINE_LOCALE(FPS)
CONFIG_DEFINE_LOCALE(Brightness)
{
{ ELanguage::English, { "Brightness", "Adjust the brightness level of the game." } }
{ ELanguage::English, { "Brightness", "Adjust the brightness level until the symbol on the left is barely visible." } }
};
CONFIG_DEFINE_LOCALE(AntiAliasing)
@@ -306,9 +308,7 @@ CONFIG_DEFINE_ENUM_LOCALE(EShadowResolution)
{
ELanguage::English,
{
{ EShadowResolution::Original, { "ORIGINAL", "Original: the game will automatically determine the resolution of the shadows." } },
{ EShadowResolution::x4096, { "4096", "High resolutions can degrade performance significantly on lower end hardware." } },
{ EShadowResolution::x8192, { "8192", "High resolutions can degrade performance significantly on lower end hardware." } },
{ EShadowResolution::Original, { "ORIGINAL", "Original: the game will automatically determine the resolution of the shadows." } }
}
}
};
@@ -353,7 +353,7 @@ CONFIG_DEFINE_LOCALE(XboxColorCorrection)
CONFIG_DEFINE_LOCALE(CutsceneAspectRatio)
{
{ ELanguage::English, { "Cutscene Aspect Ratio", "" } }
{ ELanguage::English, { "Cutscene Aspect Ratio", "Change the aspect ratio of the real-time cutscenes." } }
};
CONFIG_DEFINE_ENUM_LOCALE(ECutsceneAspectRatio)
@@ -361,24 +361,24 @@ CONFIG_DEFINE_ENUM_LOCALE(ECutsceneAspectRatio)
{
ELanguage::English,
{
{ ECutsceneAspectRatio::Original, { "ORIGINAL", "" } },
{ ECutsceneAspectRatio::Unlocked, { "UNLOCKED", "" } },
{ ECutsceneAspectRatio::Original, { "ORIGINAL", "Original: locks cutscenes to their original 16:9 aspect ratio." } },
{ ECutsceneAspectRatio::Unlocked, { "UNLOCKED", "Unlocked: allows cutscenes to adjust their aspect ratio to the window size.\n\nWARNING: this will introduce visual oddities past the original 16:9 aspect ratio." } },
}
}
};
CONFIG_DEFINE_LOCALE(UIScaleMode)
CONFIG_DEFINE_LOCALE(UIAlignmentMode)
{
{ ELanguage::English, { "UI Scale Mode", "Change how the UI scales to the display." } }
{ ELanguage::English, { "UI Alignment Mode", "Change how the UI aligns with the display." } }
};
CONFIG_DEFINE_ENUM_LOCALE(EUIScaleMode)
CONFIG_DEFINE_ENUM_LOCALE(EUIAlignmentMode)
{
{
ELanguage::English,
{
{ EUIScaleMode::Edge, { "EDGE", "Edge: the UI will anchor to the edges of the display." } },
{ EUIScaleMode::Centre, { "CENTER", "Center: the UI will anchor to the center of the display." } },
{ EUIAlignmentMode::Edge, { "EDGE", "Edge: the UI will align with the edges of the display." } },
{ EUIAlignmentMode::Centre, { "CENTER", "Center: the UI will align with the center of the display." } },
}
}
};
+36 -4
View File
@@ -189,8 +189,8 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
{
"Installer_Page_CheckSpace",
{
{ ELanguage::English, "The content will be installed to the program's folder.\n\nPlease confirm that you have enough free space.\n\n" },
{ ELanguage::Italian, "Il contenuto verrà installato nella cartella di questo programma. Assicurati di avere abbastanza spazio libero sul tuo hard disk.\n\n" }
{ ELanguage::English, "The content will be installed to the program's folder.\n\n" },
{ ELanguage::Italian, "Il contenuto verrà installato nella cartella di questo programma.\n\n" }
}
},
{
@@ -259,6 +259,12 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
{ ELanguage::Italian, "SALTA" }
}
},
{
"Installer_Button_Retry",
{
{ ELanguage::English, "RETRY" }
}
},
{
"Installer_Button_AddFiles",
{
@@ -297,14 +303,14 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
// Notes: message appears when clicking the "Add Files" option for the first time.
"Installer_Message_FilePickerTutorial",
{
{ ELanguage::English, "Select a digital dump.\n\nFor choosing a folder with\nextracted and unmodified\ngame files, use the\n\"Add Folder\" option instead." },
{ ELanguage::English, "Select a digital dump with\ncontent from the game.\n\nThese files can be obtained from\nyour Xbox 360 hard drive by\nfollowing the instructions on\nthe GitHub page.\n\nFor choosing a folder with extracted\nand unmodified game files, use\nthe \"Add Folder\" option instead." },
}
},
{
// Notes: message appears when clicking the "Add Folder" option for the first time.
"Installer_Message_FolderPickerTutorial",
{
{ ELanguage::English, "Select a folder that contains\nthe unmodified files that have\nbeen extracted from the game.\n\nFor choosing a digital dump,\nuse the\"Add Files\" option instead." },
{ ELanguage::English, "Select a folder that contains the\nunmodified files that have been\nextracted from the game.\n\nThese files can be obtained from\nyour Xbox 360 hard drive by\nfollowing the instructions on\nthe GitHub page.\n\nFor choosing a digital dump,\nuse the\"Add Files\" option instead." },
}
},
{
@@ -339,6 +345,20 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
{ ELanguage::Italian, "Questa opzione riavviera il gioco\nper farti installare qualsiasi DLC\nche non hai installato.\n\nHai già installato tutti i DLC.\n\nVuoi procedere comunque?" }
}
},
{
// Notes: message appears when user chooses "Quit" on the first available installation screen.
"Installer_Message_Quit",
{
{ ELanguage::English, "Are you sure you want to quit?" },
}
},
{
// Notes: message appears when user chooses "Cancel" during installation.
"Installer_Message_Cancel",
{
{ ELanguage::English, "Are you sure you want to cancel the installation?" },
}
},
{
// Notes: message appears when pressing B at the title screen.
"Title_Message_Quit",
@@ -446,6 +466,18 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
{ ELanguage::Italian, "Indietro" }
}
},
{
"Common_Quit",
{
{ ELanguage::English, "Quit" },
}
},
{
"Common_Cancel",
{
{ ELanguage::English, "Cancel" }
}
},
{
"Common_Reset",
{
+3 -3
View File
@@ -203,12 +203,12 @@ int main(int argc, char *argv[])
if (!Video::CreateHostDevice(sdlVideoDriver))
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
return 1;
std::_Exit(1);
}
if (!InstallerWizard::Run(GAME_INSTALL_DIRECTORY, isGameInstalled && forceDLCInstaller))
{
return 1;
std::_Exit(0);
}
}
@@ -223,7 +223,7 @@ int main(int argc, char *argv[])
if (!Video::CreateHostDevice(sdlVideoDriver))
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
return 1;
std::_Exit(1);
}
}
@@ -8,7 +8,7 @@
#include <user/paths.h>
#include <app.h>
static bool g_faderBegun = false;
static std::atomic<bool> g_faderBegun = false;
bool g_quitMessageOpen = false;
static int g_quitMessageResult = -1;
@@ -16,39 +16,29 @@ static int g_quitMessageResult = -1;
static std::atomic<bool> g_corruptSaveMessageOpen = false;
static int g_corruptSaveMessageResult = -1;
static bool g_corruptAchievementsMessageOpen = false;
static std::atomic<bool> g_corruptAchievementsMessageOpen = false;
static int g_corruptAchievementsMessageResult = -1;
static bool g_updateAvailableMessageOpen = false;
static std::atomic<bool> g_updateAvailableMessageOpen = false;
static int g_updateAvailableMessageResult = -1;
static bool ProcessQuitMessage()
{
if (g_corruptSaveMessageOpen)
return false;
if (!g_quitMessageOpen)
return false;
if (g_faderBegun)
return true;
std::array<std::string, 2> options = { Localise("Common_Yes"), Localise("Common_No") };
if (MessageWindow::Open(Localise("Title_Message_Quit"), &g_quitMessageResult, options, 1) == MSG_CLOSED)
{
switch (g_quitMessageResult)
if (!g_quitMessageResult)
{
case 0:
Fader::FadeOut(1, []() { App::Exit(); });
g_faderBegun = true;
break;
case 1:
g_quitMessageOpen = false;
g_quitMessageResult = -1;
break;
Fader::FadeOut(1, []() { App::Exit(); });
g_faderBegun = true;
}
g_quitMessageOpen = false;
g_quitMessageResult = -1;
}
return true;
@@ -86,6 +76,7 @@ static bool ProcessCorruptAchievementsMessage()
AchievementManager::Save(true);
g_corruptAchievementsMessageOpen = false;
g_corruptAchievementsMessageOpen.notify_one();
g_corruptAchievementsMessageResult = -1;
}
@@ -97,9 +88,6 @@ static bool ProcessUpdateAvailableMessage()
if (!g_updateAvailableMessageOpen)
return false;
if (g_faderBegun)
return true;
std::array<std::string, 2> options = { Localise("Common_Yes"), Localise("Common_No") };
if (MessageWindow::Open(Localise("Title_Message_UpdateAvailable"), &g_updateAvailableMessageResult, options) == MSG_CLOSED)
@@ -119,6 +107,7 @@ static bool ProcessUpdateAvailableMessage()
}
g_updateAvailableMessageOpen = false;
g_updateAvailableMessageOpen.notify_one();
g_updateAvailableMessageResult = -1;
}
@@ -137,6 +126,24 @@ PPC_FUNC(sub_822C55B0)
ctx.r3.u32 = 0;
}
void PressStartSaveLoadThreadMidAsmHook()
{
if (UpdateChecker::check() == UpdateChecker::Result::UpdateAvailable)
{
g_updateAvailableMessageOpen = true;
g_updateAvailableMessageOpen.wait(true);
g_faderBegun.wait(true);
}
AchievementManager::Load();
if (AchievementManager::Status != EAchStatus::Success)
{
g_corruptAchievementsMessageOpen = true;
g_corruptAchievementsMessageOpen.wait(true);
}
}
// SWA::CTitleStateIntro::Update
PPC_FUNC_IMPL(__imp__sub_82587E50);
PPC_FUNC(sub_82587E50)
@@ -151,21 +158,7 @@ PPC_FUNC(sub_82587E50)
{
if (auto pInputState = SWA::CInputState::GetInstance())
{
auto& rPadState = pInputState->GetPadState();
auto isAccepted = rPadState.IsTapped(SWA::eKeyState_A) || rPadState.IsTapped(SWA::eKeyState_Start);
auto isDeclined = rPadState.IsTapped(SWA::eKeyState_B);
if (isAccepted)
{
g_updateAvailableMessageOpen = UpdateChecker::check() == UpdateChecker::Result::UpdateAvailable;
AchievementManager::Load();
if (AchievementManager::Status != EAchStatus::Success)
g_corruptAchievementsMessageOpen = true;
}
if (isDeclined)
if (pInputState->GetPadState().IsTapped(SWA::eKeyState_B))
g_quitMessageOpen = true;
}
@@ -1,9 +1,12 @@
#include <api/SWA.h>
#include <cpu/guest_stack_var.h>
#include <locale/locale.h>
#include <os/logger.h>
#include <ui/button_guide.h>
#include <ui/fader.h>
#include <ui/message_window.h>
#include <ui/options_menu.h>
#include <user/achievement_manager.h>
#include <user/paths.h>
#include <app.h>
#include <exports.h>
@@ -50,12 +53,14 @@ PPC_FUNC_IMPL(__imp__sub_825882B8);
PPC_FUNC(sub_825882B8)
{
auto pTitleState = (SWA::CTitleStateBase*)g_memory.Translate(ctx.r3.u32);
auto pGameDocument = SWA::CGameDocument::GetInstance();
auto pInputState = SWA::CInputState::GetInstance();
auto& pPadState = pInputState->GetPadState();
auto isAccepted = pPadState.IsTapped(SWA::eKeyState_A) || pPadState.IsTapped(SWA::eKeyState_Start);
auto pContext = pTitleState->GetContextBase<SWA::CTitleStateBase::CTitleStateContext>();
auto isNewGameIndex = pContext->m_pTitleMenu->m_CursorIndex == 0;
auto isOptionsIndex = pContext->m_pTitleMenu->m_CursorIndex == 2;
auto isInstallIndex = pContext->m_pTitleMenu->m_CursorIndex == 3;
@@ -63,7 +68,17 @@ PPC_FUNC(sub_825882B8)
if (App::s_isSaveDataCorrupt && pContext->m_pTitleMenu->m_CursorIndex == 1)
pContext->m_pTitleMenu->m_CursorIndex = 0;
if (!OptionsMenu::s_isVisible && isOptionsIndex)
if (isNewGameIndex && isAccepted)
{
if (pContext->m_pTitleMenu->m_IsDeleteCheckMessageOpen &&
pGameDocument->m_pMember->m_pGeneralWindow->m_SelectedIndex == 1)
{
LOGN("Resetting achievements...");
AchievementManager::Reset();
}
}
else if (!OptionsMenu::s_isVisible && isOptionsIndex)
{
if (OptionsMenu::s_isRestartRequired)
{
@@ -76,7 +91,6 @@ PPC_FUNC(sub_825882B8)
{
Game_PlaySound("sys_worldmap_window");
Game_PlaySound("sys_worldmap_decide");
OptionsMenu::Open();
}
}
@@ -93,7 +107,6 @@ PPC_FUNC(sub_825882B8)
if (OptionsMenu::CanClose() && pPadState.IsTapped(SWA::eKeyState_B))
{
Game_PlaySound("sys_worldmap_cansel");
OptionsMenu::Close();
}
}
+119 -10
View File
@@ -2,7 +2,9 @@
#include <api/SWA.h>
#include <app.h>
#include <ui/game_window.h>
#include <ui/black_bar.h>
#include <gpu/video.h>
#include <xxHashMap.h>
#include "aspect_ratio_patches.h"
#include "camera_patches.h"
@@ -271,7 +273,7 @@ PPC_FUNC(sub_8258B558)
ctx.f1.f64 = offsetX + g_aspectRatioNarrowScale * 140.0f;
ctx.f2.f64 = offsetY;
if (Config::UIScaleMode == EUIScaleMode::Edge && g_aspectRatioNarrowScale >= 1.0f)
if (Config::UIAlignmentMode == EUIAlignmentMode::Edge && g_aspectRatioNarrowScale >= 1.0f)
ctx.f1.f64 += g_aspectRatioOffsetX / g_aspectRatioScale;
sub_830BB3D0(ctx, base);
@@ -293,7 +295,7 @@ PPC_FUNC(sub_8258B558)
if (textBox != NULL)
{
float value = 708.0f + g_aspectRatioNarrowScale * 140.0f;
if (Config::UIScaleMode == EUIScaleMode::Edge && g_aspectRatioNarrowScale >= 1.0f)
if (Config::UIAlignmentMode == EUIAlignmentMode::Edge && g_aspectRatioNarrowScale >= 1.0f)
value += g_aspectRatioOffsetX / g_aspectRatioScale;
PPC_STORE_U32(textBox + 0x38, reinterpret_cast<uint32_t&>(value));
@@ -339,6 +341,9 @@ enum
REPEAT_LEFT = 1 << 15,
TORNADO_DEFENSE = 1 << 16,
LOADING_BLACK_BAR_MIN = 1 << 17,
LOADING_BLACK_BAR_MAX = 1 << 18,
};
struct CsdModifier
@@ -348,7 +353,7 @@ struct CsdModifier
uint32_t cornerIndex{};
};
static const ankerl::unordered_dense::map<XXH64_hash_t, CsdModifier> g_modifiers =
static const xxHashMap<CsdModifier> g_modifiers =
{
// ui_balloon
{ HashStr("ui_balloon/window/bg"), { STRETCH } },
@@ -402,6 +407,10 @@ static const ankerl::unordered_dense::map<XXH64_hash_t, CsdModifier> g_modifiers
{ HashStr("ui_loading/n_2_d/letterbox/letterbox_top"), { STRETCH } },
{ HashStr("ui_loading/n_2_d/letterbox/black_l"), { EXTEND_LEFT | STRETCH_VERTICAL } },
{ HashStr("ui_loading/n_2_d/letterbox/black_r"), { EXTEND_RIGHT | STRETCH_VERTICAL } },
{ HashStr("ui_loading/event_viewer/black/black_top"), { LOADING_BLACK_BAR_MIN } },
{ HashStr("ui_loading/event_viewer/black/black_under"), { LOADING_BLACK_BAR_MAX } },
{ HashStr("ui_loading/pda/pda_frame/L"), { LOADING_BLACK_BAR_MIN } },
{ HashStr("ui_loading/pda/pda_frame/R"), { LOADING_BLACK_BAR_MAX } },
// ui_mediaroom
{ HashStr("ui_mediaroom/header/bg/img_1"), { EXTEND_LEFT } },
@@ -412,10 +421,40 @@ static const ankerl::unordered_dense::map<XXH64_hash_t, CsdModifier> g_modifiers
// ui_missionscreen
{ HashStr("ui_missionscreen/player_count"), { ALIGN_TOP_LEFT | SCALE } },
{ HashStr("ui_missionscreen/time_count"), { ALIGN_TOP_LEFT | SCALE } },
{ HashStr("ui_missionscreen/score_count"), { ALIGN_TOP_LEFT | SCALE } },
{ HashStr("ui_missionscreen/item_count"), { ALIGN_TOP_LEFT | SCALE } },
{ HashStr("ui_missionscreen/time_count/position_S/bg_1"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/time_count/position_S/bg_1/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/time_count/position_S/bg_2"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/time_count/position_S/bg_2/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/time_count/position_L/bg_1"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/time_count/position_L/bg_1/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/time_count/position_L/bg_2"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/time_count/position_L/bg_2/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/laptime_count"), { ALIGN_TOP_LEFT | SCALE } },
{ HashStr("ui_missionscreen/laptime_count/position_S/bg_1"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/laptime_count/position_S/bg_1/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/laptime_count/position_S/bg_2"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/laptime_count/position_S/bg_2/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/laptime_count/position_L/bg_1"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/laptime_count/position_L/bg_1/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/laptime_count/position_L/bg_2"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/laptime_count/position_L/bg_2/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/score_count"), { ALIGN_TOP_LEFT | SCALE } },
{ HashStr("ui_missionscreen/score_count/position_S/bg_1"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/score_count/position_S/bg_1/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/score_count/position_S/bg_2"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/score_count/position_S/bg_2/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/score_count/position_L/bg_1"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/score_count/position_L/bg_1/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/score_count/position_L/bg_2"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/score_count/position_L/bg_2/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/item_count"), { ALIGN_TOP_LEFT | SCALE } },
{ HashStr("ui_missionscreen/item_count/position_L/bg_1"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/item_count/position_L/bg_1/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/item_count/position_L/bg_2"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/item_count/position_L/bg_2/C_h"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
{ HashStr("ui_missionscreen/lap_count"), { ALIGN_TOP_RIGHT | SCALE } },
{ HashStr("ui_missionscreen/lap_count/position/bar"), { ALIGN_RIGHT | SCALE | EXTEND_RIGHT } },
{ HashStr("ui_missionscreen/lap_count/position/bar/R"), { SKIP } },
// ui_misson
{ HashStr("ui_misson/bg"), { STRETCH } },
@@ -878,7 +917,7 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
return;
}
if (Config::UIScaleMode == EUIScaleMode::Centre)
if (Config::UIAlignmentMode == EUIAlignmentMode::Centre)
{
if (g_aspectRatio >= WIDE_ASPECT_RATIO)
modifier.flags &= ~(ALIGN_LEFT | ALIGN_RIGHT);
@@ -1021,6 +1060,18 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
position[1] = round(y);
}
if ((modifier.flags & LOADING_BLACK_BAR_MIN) != 0)
{
auto position = getPosition(0);
BlackBar::g_loadingBlackBarMin = ImVec2{ position[0], position[1] };
BlackBar::g_loadingBlackBarAlpha = *(base + ctx.r1.u32 + 0xB);
}
else if ((modifier.flags & LOADING_BLACK_BAR_MAX) != 0)
{
auto position = getPosition(3);
BlackBar::g_loadingBlackBarMax = ImVec2{ position[0], position[1] };
}
if ((modifier.flags & REPEAT_LEFT) != 0)
{
float width = *getPosition(2) - *getPosition(0);
@@ -1147,8 +1198,8 @@ PPC_FUNC(sub_830D1EF0)
y = g_aspectRatioOffsetY + (y + 0.5f) * g_aspectRatioScale;
}
vertex[i].x = ((x - 0.5f) / Video::s_viewportWidth) * 2.0f - 1.0f;
vertex[i].y = ((y - 0.5f) / Video::s_viewportHeight) * -2.0f + 1.0f;
vertex[i].x = ((round(x) - 0.5f) / Video::s_viewportWidth) * 2.0f - 1.0f;
vertex[i].y = ((round(y) - 0.5f) / Video::s_viewportHeight) * -2.0f + 1.0f;
}
bool letterboxTop = PPC_LOAD_U8(r3.u32 + PRIMITIVE_2D_PADDING_OFFSET + 0x1);
@@ -1223,12 +1274,12 @@ static double ComputeObjGetItemX(uint32_t type)
double scaleOffset = (1280.0 * (1.0 - g_aspectRatioGameplayScale)) * g_aspectRatioScale;
if (Config::UIScaleMode == EUIScaleMode::Edge)
if (Config::UIAlignmentMode == EUIAlignmentMode::Edge)
{
if (type != 47) // Medal
x += g_aspectRatioOffsetX * 2.0 + scaleOffset;
}
else if (Config::UIScaleMode == EUIScaleMode::Centre)
else if (Config::UIAlignmentMode == EUIAlignmentMode::Centre)
{
x += g_aspectRatioOffsetX + scaleOffset;
}
@@ -1362,6 +1413,12 @@ PPC_FUNC(sub_82B8AA40)
// Restore the original letterbox value.
PPC_STORE_U8(r3.u32, letterbox);
if (letterbox)
{
// Would be nice to also push this as a 2D primitive but I really cannot be bothered right now...
BlackBar::g_inspirePillarbox = Config::CutsceneAspectRatio != ECutsceneAspectRatio::Unlocked && g_aspectRatio > WIDE_ASPECT_RATIO;
}
}
void InspireLetterboxTopMidAsmHook(PPCRegister& r3)
@@ -1444,3 +1501,55 @@ void YggdrasillRenderQuadMidAsmHook(PPCRegister& r3, PPCRegister& r6)
}
}
}
// Explicit CSD set position calls don't seem to care about the
// viewport size. This causes them to appear shifted by 1.5x,
// as the backbuffer resolution is 640x480 at 4:3. We need to account
// for this manually to make the positioning match with the original game.
static constexpr uint32_t EVIL_HUD_GUIDE_BYTE_SIZE = 0x154;
void EvilHudGuideAllocMidAsmHook(PPCRegister& r3)
{
r3.u32 += sizeof(float);
}
// SWA::Player::CEvilHudGuide::CEvilHudGuide
PPC_FUNC_IMPL(__imp__sub_82448CF0);
PPC_FUNC(sub_82448CF0)
{
*reinterpret_cast<float*>(base + ctx.r3.u32 + EVIL_HUD_GUIDE_BYTE_SIZE) = 0.0f;
__imp__sub_82448CF0(ctx, base);
}
void EvilHudGuideUpdateMidAsmHook(PPCRegister& r30, PPCRegister& f30)
{
*reinterpret_cast<float*>(g_memory.base + r30.u32 + EVIL_HUD_GUIDE_BYTE_SIZE) = f30.f64;
}
// SWA::Player::CEvilHudGuide::Update
PPC_FUNC_IMPL(__imp__sub_82449088);
PPC_FUNC(sub_82449088)
{
auto r3 = ctx.r3;
__imp__sub_82449088(ctx, base);
float positionX = *reinterpret_cast<float*>(base + r3.u32 + EVIL_HUD_GUIDE_BYTE_SIZE);
constexpr uint32_t OFFSETS[] = { 312, 320 };
for (const auto offset : OFFSETS)
{
uint32_t scene = PPC_LOAD_U32(r3.u32 + offset + 0x4);
if (scene != NULL)
{
scene = PPC_LOAD_U32(scene + 0x4);
if (scene != NULL)
{
ctx.r3.u32 = scene;
ctx.f1.f64 = (1.5 - 0.5 * g_aspectRatioNarrowScale) * positionX;
ctx.f2.f64 = 0.0;
sub_830BB3D0(ctx, base);
}
}
}
}
+35 -4
View File
@@ -115,10 +115,7 @@ PPC_FUNC(sub_8312DBF8)
constexpr auto INTERVAL = 1000000000ns / 60;
auto next = now + (INTERVAL - now.time_since_epoch() % INTERVAL);
std::this_thread::sleep_for(std::chrono::floor<std::chrono::milliseconds>(next - now - 1ms));
while (std::chrono::steady_clock::now() < next)
std::this_thread::yield();
std::this_thread::sleep_until(next);
}
void WaitVsyncMidAsmHook()
@@ -128,3 +125,37 @@ void WaitVsyncMidAsmHook()
void ApplicationFrameLimiterMidAsmHook()
{
}
// Tornado Defense boss increments timers without respecting delta time.
// We run the update function with a 30 FPS time step to ensure all timers update at the correct rate.
static constexpr size_t EX_STAGE_BOSS_STATE_BATTLE_SIZE = 0x70;
void CExStageBossCStateBattleAllocMidAsmHook(PPCRegister& r3)
{
r3.u32 += sizeof(float);
}
void CExStageBossCStateBattleCtorMidAsmHook(PPCRegister& r3)
{
new (g_memory.base + r3.u32 + EX_STAGE_BOSS_STATE_BATTLE_SIZE) float(0);
}
// SWA::CExStageBoss::CStateBattle::Update
PPC_FUNC_IMPL(__imp__sub_82B00D00);
PPC_FUNC(sub_82B00D00)
{
constexpr auto referenceDeltaTime = 1.0f / 30.0f;
constexpr auto deltaTimeTolerance = 0.0001f;
auto pElapsedTime = (float*)(base + ctx.r3.u32 + EX_STAGE_BOSS_STATE_BATTLE_SIZE);
*pElapsedTime += std::min(App::s_deltaTime, 1.0 / 15.0);
if ((*pElapsedTime + deltaTimeTolerance) > referenceDeltaTime)
{
__imp__sub_82B00D00(ctx, base);
*pElapsedTime -= referenceDeltaTime;
}
*pElapsedTime = std::max(*pElapsedTime, 0.0f);
}
@@ -9,10 +9,10 @@ static class FrontendListener : public SDLEventListener
bool m_isF8KeyDown = false;
public:
void OnSDLEvent(SDL_Event* event) override
bool OnSDLEvent(SDL_Event* event) override
{
if (!Config::HUDToggleHotkey || OptionsMenu::s_isVisible)
return;
return false;
switch (event->type)
{
@@ -34,6 +34,8 @@ public:
m_isF8KeyDown = event->key.keysym.sym != SDLK_F8;
break;
}
return false;
}
}
g_frontendListener;
+4 -2
View File
@@ -121,10 +121,10 @@ public:
}
}
void OnSDLEvent(SDL_Event* event) override
bool OnSDLEvent(SDL_Event* event) override
{
if (!hid::IsInputAllowed())
return;
return false;
switch (event->type)
{
@@ -202,6 +202,8 @@ public:
ms_touchpadFingerCount--;
break;
}
return false;
}
}
g_sdlEventListenerForInputPatches;
+5 -6
View File
@@ -1,20 +1,19 @@
#pragma once
inline const char* g_credits[] =
inline std::array<const char*, 14> g_credits =
{
"Skyth",
"Hyper",
"Darío",
"Sajid",
"DeaThProj",
"RadiantDerg",
"PTKay",
"DeaThProj",
"SuperSonic16",
"NextinHKRY",
"M&M",
"saguinee",
"LadyLunanova",
"LJSTAR"
"LJSTAR",
"Goalringmod27",
"M&M"
};
inline size_t g_creditsSize = 12;
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION_MILESTONE="Beta 1"
VERSION_MILESTONE="Beta 2"
VERSION_MAJOR=1
VERSION_MINOR=0
VERSION_REVISION=0
+2 -2
View File
@@ -4,7 +4,7 @@ class ISDLEventListener
{
public:
virtual ~ISDLEventListener() = default;
virtual void OnSDLEvent(SDL_Event* event) = 0;
virtual bool OnSDLEvent(SDL_Event* event) = 0;
};
extern std::vector<ISDLEventListener*>& GetEventListeners();
@@ -17,5 +17,5 @@ public:
GetEventListeners().emplace_back(this);
}
void OnSDLEvent(SDL_Event* event) override {}
bool OnSDLEvent(SDL_Event* event) override { return false; }
};
+1 -1
View File
@@ -197,7 +197,7 @@ static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievemen
ImVec2 marqueeMin = { textMarqueeX, min.y };
ImVec2 marqueeMax = { max.x - Scale(10) /* timestamp margin X */, max.y };
SetMarqueeFade(marqueeMin, marqueeMax, Scale(32));
SetHorizontalMarqueeFade(marqueeMin, marqueeMax, Scale(32));
if (isSelected && textX + textSize.x >= max.x - Scale(10))
{
+1 -1
View File
@@ -167,7 +167,7 @@ void AchievementOverlay::Draw()
void AchievementOverlay::Open(int id)
{
if (s_isVisible)
if (s_isVisible && !g_isClosing)
{
s_queue.emplace(id);
return;
+58
View File
@@ -0,0 +1,58 @@
#include "black_bar.h"
#include <patches/aspect_ratio_patches.h>
void BlackBar::Draw()
{
if (g_inspirePillarbox)
{
auto drawList = ImGui::GetBackgroundDrawList();
auto& res = ImGui::GetIO().DisplaySize;
float width = (res.x - (res.y * 16.0f / 9.0f)) / 2.0f;
drawList->AddRectFilled(
{ 0.0f, 0.0f },
{ width, res.y },
IM_COL32_BLACK);
drawList->AddRectFilled(
{ res.x - width, 0.0f },
res,
IM_COL32_BLACK);
g_inspirePillarbox = false;
}
if (g_loadingBlackBarAlpha != 0)
{
auto drawList = ImGui::GetBackgroundDrawList();
auto& res = ImGui::GetIO().DisplaySize;
if (g_aspectRatio > WIDE_ASPECT_RATIO)
{
drawList->AddRectFilled(
{ 0.0f, 0.0f },
{ g_loadingBlackBarMin.x, g_loadingBlackBarMax.y },
IM_COL32(0, 0, 0, g_loadingBlackBarAlpha));
drawList->AddRectFilled(
{ g_loadingBlackBarMax.x, g_loadingBlackBarMin.y },
res,
IM_COL32(0, 0, 0, g_loadingBlackBarAlpha));
}
else if (g_aspectRatio < NARROW_ASPECT_RATIO)
{
drawList->AddRectFilled(
{ 0.0f, 0.0f },
{ g_loadingBlackBarMax.x, g_loadingBlackBarMin.y },
IM_COL32(0, 0, 0, g_loadingBlackBarAlpha));
drawList->AddRectFilled(
{ g_loadingBlackBarMin.x, g_loadingBlackBarMax.y },
res,
IM_COL32(0, 0, 0, g_loadingBlackBarAlpha));
}
g_loadingBlackBarAlpha = 0;
}
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
struct BlackBar
{
static inline bool g_inspirePillarbox;
static inline ImVec2 g_loadingBlackBarMin;
static inline ImVec2 g_loadingBlackBarMax;
static inline uint8_t g_loadingBlackBarAlpha;
static void Draw();
};
+11 -4
View File
@@ -38,7 +38,8 @@ std::unordered_map<EButtonIcon, float> g_iconWidths =
{ EButtonIcon::Start, 40 },
{ EButtonIcon::Back, 40 },
{ EButtonIcon::LMB, 40 },
{ EButtonIcon::Enter, 40 }
{ EButtonIcon::Enter, 40 },
{ EButtonIcon::Escape, 40 },
};
std::unordered_map<EButtonIcon, float> g_iconHeights =
@@ -56,7 +57,8 @@ std::unordered_map<EButtonIcon, float> g_iconHeights =
{ EButtonIcon::Start, 40 },
{ EButtonIcon::Back, 40 },
{ EButtonIcon::LMB, 40 },
{ EButtonIcon::Enter, 40 }
{ EButtonIcon::Enter, 40 },
{ EButtonIcon::Escape, 40 },
};
std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon icon)
@@ -124,12 +126,17 @@ std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon
break;
case EButtonIcon::LMB:
btn = PIXELS_TO_UV_COORDS(256, 128, 0, 0, 128, 128);
btn = PIXELS_TO_UV_COORDS(384, 128, 0, 0, 128, 128);
texture = g_upKBMIcons.get();
break;
case EButtonIcon::Enter:
btn = PIXELS_TO_UV_COORDS(256, 128, 128, 0, 128, 128);
btn = PIXELS_TO_UV_COORDS(384, 128, 128, 0, 128, 128);
texture = g_upKBMIcons.get();
break;
case EButtonIcon::Escape:
btn = PIXELS_TO_UV_COORDS(384, 128, 256, 0, 128, 128);
texture = g_upKBMIcons.get();
break;
}
+2 -1
View File
@@ -20,7 +20,8 @@ enum class EButtonIcon
// Keyboard + Mouse (temporary)
LMB,
Enter
Enter,
Escape
};
enum class EButtonAlignment
+12 -18
View File
@@ -9,7 +9,7 @@
#if _WIN32
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
#include <shellscalingapi.h>
#endif
#include <res/images/game_icon.bmp.h>
@@ -24,7 +24,12 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
ImGui_ImplSDL2_ProcessEvent(event);
for (auto listener : GetEventListeners())
listener->OnSDLEvent(event);
{
if (listener->OnSDLEvent(event))
{
return 0;
}
}
switch (event->type)
{
@@ -141,20 +146,6 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
break;
}
if (!GameWindow::IsFullscreen())
{
if (event->type == SDL_CONTROLLERBUTTONDOWN || event->type == SDL_CONTROLLERBUTTONUP || event->type == SDL_CONTROLLERAXISMOTION)
{
// Hide mouse cursor when controller input is detected.
SDL_ShowCursor(SDL_DISABLE);
}
else if (event->type == SDL_MOUSEMOTION)
{
// Restore mouse cursor when mouse input is detected.
SDL_ShowCursor(SDL_ENABLE);
}
}
return 0;
}
@@ -179,7 +170,7 @@ void GameWindow::Init(const char* sdlVideoDriver)
SDL_AddEventWatch(Window_OnSDLEvent, s_pWindow);
#ifdef _WIN32
SetProcessDPIAware();
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
#endif
Config::WindowSize.LockCallback = [](ConfigDef<int32_t>* def)
@@ -437,7 +428,7 @@ void GameWindow::ResetDimensions()
uint32_t GameWindow::GetWindowFlags()
{
uint32_t flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE;
uint32_t flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
if (Config::WindowState == EWindowState::Maximised)
flags |= SDL_WINDOW_MAXIMIZED;
@@ -475,6 +466,9 @@ void GameWindow::SetDisplay(int displayIndex)
if (!IsFullscreen())
return;
if (GetDisplay() == displayIndex)
return;
s_isChangingDisplay = true;
SDL_Rect bounds;
+73 -57
View File
@@ -6,20 +6,17 @@
#include <res/images/common/general_window.dds.h>
#include <res/images/common/light.dds.h>
#include <res/images/common/select_fade.dds.h>
#include <res/images/common/select_fill.dds.h>
#include <res/images/common/select.dds.h>
std::unique_ptr<GuestTexture> g_texGeneralWindow;
std::unique_ptr<GuestTexture> g_texLight;
std::unique_ptr<GuestTexture> g_texSelectFade;
std::unique_ptr<GuestTexture> g_texSelectFill;
std::unique_ptr<GuestTexture> g_texSelect;
void InitImGuiUtils()
{
g_texGeneralWindow = LOAD_ZSTD_TEXTURE(g_general_window);
g_texLight = LOAD_ZSTD_TEXTURE(g_light);
g_texSelectFade = LOAD_ZSTD_TEXTURE(g_select_fade);
g_texSelectFill = LOAD_ZSTD_TEXTURE(g_select_fill);
g_texSelect = LOAD_ZSTD_TEXTURE(g_select);
}
void SetGradient(const ImVec2& min, const ImVec2& max, ImU32 top, ImU32 bottom)
@@ -80,7 +77,7 @@ void ResetTextSkew()
SetScale({ 1.0f, 1.0f });
}
void SetMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScaleLeft, float fadeScaleRight)
{
auto callbackData = AddImGuiCallback(ImGuiCallback::SetMarqueeFade);
callbackData->setMarqueeFade.boundsMin[0] = min.x;
@@ -88,8 +85,30 @@ void SetMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
callbackData->setMarqueeFade.boundsMax[0] = max.x;
callbackData->setMarqueeFade.boundsMax[1] = max.y;
SetShaderModifier(IMGUI_SHADER_MODIFIER_MARQUEE_FADE);
SetScale({ fadeScale, 1.0f });
SetShaderModifier(IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE);
SetScale({ fadeScaleLeft, fadeScaleRight });
}
void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
{
SetHorizontalMarqueeFade(min, max, fadeScale, fadeScale);
}
void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScaleTop, float fadeScaleBottom)
{
auto callbackData = AddImGuiCallback(ImGuiCallback::SetMarqueeFade);
callbackData->setMarqueeFade.boundsMin[0] = min.x;
callbackData->setMarqueeFade.boundsMin[1] = min.y;
callbackData->setMarqueeFade.boundsMax[0] = max.x;
callbackData->setMarqueeFade.boundsMax[1] = max.y;
SetShaderModifier(IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE);
SetScale({ fadeScaleTop, fadeScaleBottom });
}
void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
{
SetVerticalMarqueeFade(min, max, fadeScale, fadeScale);
}
void ResetMarqueeFade()
@@ -341,7 +360,8 @@ std::string Truncate(const std::string& input, size_t maxLength, bool useEllipsi
return input;
}
std::pair<std::string, std::map<std::string, std::string>> RemoveRubyAnnotations(const char* input) {
std::pair<std::string, std::map<std::string, std::string>> RemoveRubyAnnotations(const char* input)
{
std::string output;
std::map<std::string, std::string> rubyMap;
std::string currentMain, currentRuby;
@@ -388,7 +408,8 @@ std::pair<std::string, std::map<std::string, std::string>> RemoveRubyAnnotations
return { output, rubyMap };
}
std::string ReAddRubyAnnotations(const std::string_view& wrappedText, const std::map<std::string, std::string>& rubyMap) {
std::string ReAddRubyAnnotations(const std::string_view& wrappedText, const std::map<std::string, std::string>& rubyMap)
{
std::string annotatedText;
size_t idx = 0;
size_t length = wrappedText.length();
@@ -419,7 +440,7 @@ std::string ReAddRubyAnnotations(const std::string_view& wrappedText, const std:
return annotatedText;
}
std::vector<std::string> Split(const char* strStart, const ImFont *font, float fontSize, float maxWidth)
std::vector<std::string> Split(const char* strStart, const ImFont* font, float fontSize, float maxWidth)
{
if (!strStart)
return {};
@@ -433,6 +454,7 @@ std::vector<std::string> Split(const char* strStart, const ImFont *font, float f
const char *lineStart = strStart;
const bool wordWrapEnabled = (maxWidth > 0.0f);
const char *wordWrapEOL = nullptr;
while (*str != 0)
{
if (wordWrapEnabled)
@@ -560,10 +582,9 @@ std::vector<std::string> RemoveAnnotationFromParagraph(const std::vector<std::st
for (auto& annotatedLine : paragraph.lines)
{
std::string annotationRemovedLine = "";
for (const auto& segment : annotatedLine)
{
annotationRemovedLine += segment.text;
}
result.push_back(annotationRemovedLine);
}
@@ -576,9 +597,7 @@ std::string RemoveAnnotationFromParagraphLine(const std::vector<TextSegment>& an
std::string result = "";
for (auto& segment : annotatedLine)
{
result += segment.text;
}
return result;
}
@@ -591,25 +610,19 @@ ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMar
const auto paragraph = CalculateAnnotatedParagraph(lines);
std::vector<std::string> annotationRemovedLines;
for (const auto& line : paragraph.lines)
{
annotationRemovedLines.emplace_back(RemoveAnnotationFromParagraphLine(line));
}
for (size_t i = 0; i < annotationRemovedLines.size(); i++)
{
auto& line = annotationRemovedLines[i];
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, line.c_str());
auto annotationSize = font->CalcTextSizeA(fontSize * ANNOTATION_FONT_SIZE_MODIFIER, FLT_MAX, 0, "");
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, annotationRemovedLines[i].c_str());
x = std::max(x, textSize.x);
y += textSize.y + Scale(lineMargin);
if (paragraph.annotated)
{
y += annotationSize.y;
}
if (paragraph.annotated && i != (annotationRemovedLines.size() - 1))
y += fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
}
return { x, y };
@@ -617,23 +630,27 @@ ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMar
ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidth, float lineMargin, const char* text)
{
return MeasureCentredParagraph(font, fontSize, lineMargin, Split(text, font, fontSize, maxWidth));
const auto input = RemoveRubyAnnotations(text);
auto lines = Split(input.first.c_str(), font, fontSize, maxWidth);
for (auto& line : lines)
line = ReAddRubyAnnotations(line, input.second);
return MeasureCentredParagraph(font, fontSize, lineMargin, lines);
}
void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function<void(const char*, ImVec2)> drawMethod, std::function<void(const char*, float, ImVec2)> annotationDrawMethod, bool isCentred)
{
float annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
const auto input = RemoveRubyAnnotations(text);
auto lines = Split(input.first.c_str(), font, fontSize, maxWidth);
for (auto& line : lines)
{
line = ReAddRubyAnnotations(line, input.second);
}
auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines);
float offsetY = 0.0f;
auto offsetY = 0.0f;
const auto paragraph = CalculateAnnotatedParagraph(lines);
@@ -643,9 +660,8 @@ void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, c
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, annotationRemovedLine.c_str());
auto annotationSize = font->CalcTextSizeA(annotationFontSize, FLT_MAX, 0, "");
float textX = pos.x;
float textY = pos.y + offsetY;
auto textX = pos.x;
auto textY = pos.y + offsetY;
if (isCentred)
{
@@ -669,14 +685,14 @@ void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, c
}
drawMethod(segment.text.c_str(), { textX, textY });
textX += textSize.x;
}
offsetY += textSize.y + Scale(lineMargin);
if (paragraph.annotated)
{
offsetY += annotationSize.y;
}
}
}
@@ -741,32 +757,32 @@ void DrawSelectionContainer(ImVec2 min, ImVec2 max, bool fadeTop)
auto centre = PIXELS_TO_UV_COORDS(64, 64, 11, 0, 8, 50);
auto right = PIXELS_TO_UV_COORDS(64, 64, 19, 0, 11, 50);
drawList->AddImage(g_texSelectFade.get(), min, { min.x + commonWidth, max.y }, GET_UV_COORDS(left), colour);
drawList->AddImage(g_texSelectFade.get(), { min.x + commonWidth, min.y }, { max.x - commonWidth, max.y }, GET_UV_COORDS(centre), colour);
drawList->AddImage(g_texSelectFade.get(), { max.x - commonWidth, min.y }, max, GET_UV_COORDS(right), colour);
drawList->AddImage(g_texSelect.get(), min, { min.x + commonWidth, max.y }, GET_UV_COORDS(left), colour);
drawList->AddImage(g_texSelect.get(), { min.x + commonWidth, min.y }, { max.x - commonWidth, max.y }, GET_UV_COORDS(centre), colour);
drawList->AddImage(g_texSelect.get(), { max.x - commonWidth, min.y }, max, GET_UV_COORDS(right), colour);
return;
}
auto tl = PIXELS_TO_UV_COORDS(64, 64, 0, 0, 11, 24);
auto tc = PIXELS_TO_UV_COORDS(64, 64, 11, 0, 8, 24);
auto tr = PIXELS_TO_UV_COORDS(64, 64, 19, 0, 11, 24);
auto cl = PIXELS_TO_UV_COORDS(64, 64, 0, 24, 11, 2);
auto cc = PIXELS_TO_UV_COORDS(64, 64, 11, 24, 8, 2);
auto cr = PIXELS_TO_UV_COORDS(64, 64, 19, 24, 11, 2);
auto bl = PIXELS_TO_UV_COORDS(64, 64, 0, 26, 11, 24);
auto bc = PIXELS_TO_UV_COORDS(64, 64, 11, 26, 8, 24);
auto br = PIXELS_TO_UV_COORDS(64, 64, 19, 26, 11, 24);
auto tl = PIXELS_TO_UV_COORDS(64, 64, 34, 0, 11, 24);
auto tc = PIXELS_TO_UV_COORDS(64, 64, 45, 0, 8, 24);
auto tr = PIXELS_TO_UV_COORDS(64, 64, 53, 0, 11, 24);
auto cl = PIXELS_TO_UV_COORDS(64, 64, 34, 24, 11, 2);
auto cc = PIXELS_TO_UV_COORDS(64, 64, 45, 24, 8, 2);
auto cr = PIXELS_TO_UV_COORDS(64, 64, 53, 24, 11, 2);
auto bl = PIXELS_TO_UV_COORDS(64, 64, 34, 26, 11, 24);
auto bc = PIXELS_TO_UV_COORDS(64, 64, 45, 26, 8, 24);
auto br = PIXELS_TO_UV_COORDS(64, 64, 53, 26, 11, 24);
drawList->AddImage(g_texSelectFill.get(), min, { min.x + commonWidth, min.y + commonHeight }, GET_UV_COORDS(tl), colour);
drawList->AddImage(g_texSelectFill.get(), { min.x + commonWidth, min.y }, { max.x - commonWidth, min.y + commonHeight }, GET_UV_COORDS(tc), colour);
drawList->AddImage(g_texSelectFill.get(), { max.x - commonWidth, min.y }, { max.x, min.y + commonHeight }, GET_UV_COORDS(tr), colour);
drawList->AddImage(g_texSelectFill.get(), { min.x, min.y + commonHeight }, { min.x + commonWidth, max.y - commonHeight }, GET_UV_COORDS(cl), colour);
drawList->AddImage(g_texSelectFill.get(), { min.x + commonWidth, min.y + commonHeight }, { max.x - commonWidth, max.y - commonHeight }, GET_UV_COORDS(cc), colour);
drawList->AddImage(g_texSelectFill.get(), { max.x - commonWidth, min.y + commonHeight }, { max.x, max.y - commonHeight }, GET_UV_COORDS(cr), colour);
drawList->AddImage(g_texSelectFill.get(), { min.x, max.y - commonHeight }, { min.x + commonWidth, max.y }, GET_UV_COORDS(bl), colour);
drawList->AddImage(g_texSelectFill.get(), { min.x + commonWidth, max.y - commonHeight }, { max.x - commonWidth, max.y }, GET_UV_COORDS(bc), colour);
drawList->AddImage(g_texSelectFill.get(), { max.x - commonWidth, max.y - commonHeight }, { max.x, max.y }, GET_UV_COORDS(br), colour);
drawList->AddImage(g_texSelect.get(), min, { min.x + commonWidth, min.y + commonHeight }, GET_UV_COORDS(tl), colour);
drawList->AddImage(g_texSelect.get(), { min.x + commonWidth, min.y }, { max.x - commonWidth, min.y + commonHeight }, GET_UV_COORDS(tc), colour);
drawList->AddImage(g_texSelect.get(), { max.x - commonWidth, min.y }, { max.x, min.y + commonHeight }, GET_UV_COORDS(tr), colour);
drawList->AddImage(g_texSelect.get(), { min.x, min.y + commonHeight }, { min.x + commonWidth, max.y - commonHeight }, GET_UV_COORDS(cl), colour);
drawList->AddImage(g_texSelect.get(), { min.x + commonWidth, min.y + commonHeight }, { max.x - commonWidth, max.y - commonHeight }, GET_UV_COORDS(cc), colour);
drawList->AddImage(g_texSelect.get(), { max.x - commonWidth, min.y + commonHeight }, { max.x, max.y - commonHeight }, GET_UV_COORDS(cr), colour);
drawList->AddImage(g_texSelect.get(), { min.x, max.y - commonHeight }, { min.x + commonWidth, max.y }, GET_UV_COORDS(bl), colour);
drawList->AddImage(g_texSelect.get(), { min.x + commonWidth, max.y - commonHeight }, { max.x - commonWidth, max.y }, GET_UV_COORDS(bc), colour);
drawList->AddImage(g_texSelect.get(), { max.x - commonWidth, max.y - commonHeight }, { max.x, max.y }, GET_UV_COORDS(br), colour);
}
void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha)
+5 -3
View File
@@ -18,8 +18,7 @@ constexpr float ANNOTATION_FONT_SIZE_MODIFIER = 0.6f;
extern std::unique_ptr<GuestTexture> g_texGeneralWindow;
extern std::unique_ptr<GuestTexture> g_texLight;
extern std::unique_ptr<GuestTexture> g_texSelectFade;
extern std::unique_ptr<GuestTexture> g_texSelectFill;
extern std::unique_ptr<GuestTexture> g_texSelect;
struct TextSegment {
bool annotated;
@@ -42,7 +41,10 @@ void SetOrigin(ImVec2 origin);
void SetScale(ImVec2 scale);
void SetTextSkew(float yCenter, float skewScale);
void ResetTextSkew();
void SetMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale);
void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScaleLeft, float fadeScaleRight);
void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale);
void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScaleTop, float fadeScaleBottom);
void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale);
void ResetMarqueeFade();
void SetOutline(float outline);
void ResetOutline();
+291 -119
View File
@@ -54,6 +54,7 @@ static constexpr double CONTAINER_INNER_TIME = SCANLINES_ANIMATION_DURATION + CO
static constexpr double CONTAINER_INNER_DURATION = 15.0;
static constexpr double ALL_ANIMATIONS_FULL_DURATION = CONTAINER_INNER_TIME + CONTAINER_INNER_DURATION;
static constexpr double QUITTING_EXTRA_DURATION = 60.0;
static constexpr double INSTALL_ICONS_FADE_IN_ANIMATION_TIME = 0.0;
static constexpr double INSTALL_ICONS_FADE_IN_ANIMATION_DURATION = 15.0;
@@ -77,7 +78,7 @@ constexpr float CONTAINER_HEIGHT = 246.0f;
constexpr float SIDE_CONTAINER_WIDTH = CONTAINER_WIDTH / 2.0f;
constexpr float BOTTOM_X_GAP = 4.0f;
constexpr float BOTTOM_Y_GAP = 6.0f;
constexpr float BOTTOM_Y_GAP = 5.0f;
constexpr float CONTAINER_BUTTON_WIDTH = 250.0f;
constexpr float CONTAINER_BUTTON_GAP = 9.0f;
constexpr float BUTTON_HEIGHT = 22.0f;
@@ -98,6 +99,7 @@ static double g_arrowCircleCurrentRotation = 0.0;
static double g_appearTime = 0.0;
static double g_disappearTime = DBL_MAX;
static bool g_isDisappearing = false;
static bool g_isQuitting = false;
static std::filesystem::path g_installPath;
static std::filesystem::path g_gameSourcePath;
@@ -118,6 +120,8 @@ static double g_installerEndTime = DBL_MAX;
static float g_installerProgressRatioCurrent = 0.0f;
static std::atomic<float> g_installerProgressRatioTarget = 0.0f;
static std::atomic<bool> g_installerFinished = false;
static std::atomic<bool> g_installerHalted = false;
static std::atomic<bool> g_installerCancelled = false;
static bool g_installerFailed = false;
static std::string g_installerErrorMessage;
@@ -133,9 +137,17 @@ enum class WizardPage
InstallFailed,
};
enum class MessagePromptSource
{
Unknown,
Next,
Back
};
static WizardPage g_firstPage = WizardPage::SelectLanguage;
static WizardPage g_currentPage = g_firstPage;
static std::string g_currentMessagePrompt = "";
static MessagePromptSource g_currentMessagePromptSource = MessagePromptSource::Unknown;
static bool g_currentMessagePromptConfirmation = false;
static std::list<std::filesystem::path> g_currentPickerResults;
static std::atomic<bool> g_currentPickerResultsReady = false;
@@ -151,16 +163,32 @@ static ImVec2 g_joypadAxis = {};
static int g_currentCursorIndex = -1;
static int g_currentCursorDefault = 0;
static bool g_currentCursorAccepted = false;
static bool g_currentCursorBack = false;
static std::vector<std::pair<ImVec2, ImVec2>> g_currentCursorRects;
static std::string g_creditsStr;
class SDLEventListenerForInstaller : public SDLEventListener
{
public:
void OnSDLEvent(SDL_Event *event) override
bool OnSDLEvent(SDL_Event *event) override
{
if (!InstallerWizard::s_isVisible || !g_currentMessagePrompt.empty() || g_currentPickerVisible || !hid::IsInputAllowed())
return;
if (!InstallerWizard::s_isVisible)
return false;
bool noModals = g_currentMessagePrompt.empty() && !g_currentPickerVisible;
if (event->type == SDL_QUIT && g_currentPage == WizardPage::Installing)
{
// Pretend the back button was pressed if the user tried quitting during installation.
// This condition is above the rest of the event processing as we want to block the exit
// button while there's confirmation message is open as well.
if (noModals)
g_currentCursorBack = true;
return true;
}
if (!noModals || !hid::IsInputAllowed())
return false;
constexpr float AxisValueRange = 32767.0f;
constexpr float AxisTapRange = 0.5f;
@@ -185,6 +213,9 @@ public:
case SDL_SCANCODE_KP_ENTER:
g_currentCursorAccepted = (g_currentCursorIndex >= 0);
break;
case SDL_SCANCODE_ESCAPE:
g_currentCursorBack = true;
break;
}
break;
@@ -209,6 +240,9 @@ public:
case SDL_CONTROLLER_BUTTON_A:
g_currentCursorAccepted = (g_currentCursorIndex >= 0);
break;
case SDL_CONTROLLER_BUTTON_B:
g_currentCursorBack = true;
break;
}
break;
@@ -307,6 +341,8 @@ public:
g_currentCursorIndex = newCursorIndex;
}
return false;
}
}
g_sdlEventListenerForInstaller;
@@ -797,7 +833,7 @@ static void DrawDescriptionContainer()
ImVec2 textMin = { g_aspectRatioOffsetX + Scale(CONTAINER_X), textPos.y };
ImVec2 textMax = { g_aspectRatioOffsetX + Scale(CONTAINER_X) + Scale(CONTAINER_WIDTH), g_aspectRatioOffsetY + Scale(CONTAINER_Y) + Scale(CONTAINER_HEIGHT) };
SetMarqueeFade(textMin, textMax, Scale(32));
SetHorizontalMarqueeFade(textMin, textMax, Scale(32));
DrawTextWithMarquee(g_seuratFont, fontSize, textPos, textMin, textMax, colWhite, g_creditsStr.c_str(), g_installerEndTime, 0.9, Scale(200));
ResetMarqueeFade();
}
@@ -807,15 +843,47 @@ static void DrawDescriptionContainer()
DrawContainer(sideMin, sideMax, false);
drawList->PopClipRect();
if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0)
EButtonIcon backIcon;
EButtonIcon selectIcon;
if (hid::IsInputDeviceController())
{
auto icon = hid::IsInputDeviceController()
? EButtonIcon::A
: hid::g_inputDevice == hid::EInputDevice::Keyboard
? EButtonIcon::Enter
: EButtonIcon::LMB;
backIcon = EButtonIcon::B;
selectIcon = EButtonIcon::A;
}
else if (hid::g_inputDevice == hid::EInputDevice::Keyboard)
{
backIcon = EButtonIcon::Escape;
selectIcon = EButtonIcon::Enter;
}
else
{
backIcon = EButtonIcon::Escape;
selectIcon = EButtonIcon::LMB;
}
ButtonGuide::Open(Button(Localise("Common_Select"), icon));
if (g_currentPage == WizardPage::InstallSucceeded && textAlpha >= 1.0)
{
ButtonGuide::Open(Button(Localise("Common_Select"), selectIcon));
}
else if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0)
{
const char *backKey = "Common_Back";
if ((g_currentPage == g_firstPage) || (g_currentPage == WizardPage::InstallFailed))
{
backKey = "Common_Quit";
}
std::array<Button, 2> buttons =
{
Button(Localise("Common_Select"), selectIcon),
Button(Localise(backKey), backIcon)
};
ButtonGuide::Open(buttons);
}
else if (g_currentPage == WizardPage::Installing)
{
ButtonGuide::Open(Button(Localise("Common_Cancel"), backIcon));
}
else
{
@@ -952,10 +1020,11 @@ static void DrawSourceButton(ButtonColumn buttonColumn, float yRatio, const char
ImVec2 min = { minX, g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT - CONTAINER_BUTTON_GAP - BUTTON_HEIGHT - minusY) };
ImVec2 max = { maxX, g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT - CONTAINER_BUTTON_GAP - minusY) };
auto alphaMotion = ComputeMotionInstaller(g_appearTime, g_disappearTime, CONTAINER_INNER_TIME, CONTAINER_INNER_DURATION);
auto lightSize = Scale(14);
DrawButton(min, max, sourceText, true, sourceSet, buttonPressed, (max.x - min.x) - lightSize * 10);
DrawToggleLight({ min.x + lightSize, min.y + ((max.y - min.y) - lightSize) / 2 + Scale(1) }, sourceSet, sourceSet ? 1.0f : 0.5f);
DrawButton(min, max, sourceText, true, sourceSet, buttonPressed, ((max.x - min.x) * 0.7) / g_aspectRatioScale);
DrawToggleLight({ min.x + lightSize, min.y + ((max.y - min.y) - lightSize) / 2 + Scale(1) }, sourceSet, (sourceSet ? 1.0f : 0.5f) * alphaMotion);
}
static void DrawProgressBar(float progressRatio)
@@ -965,9 +1034,9 @@ static void DrawProgressBar(float progressRatio)
float alpha = 1.0;
const uint32_t innerColor0 = IM_COL32(0, 65, 0, 255 * alpha);
const uint32_t innerColor1 = IM_COL32(0, 32, 0, 255 * alpha);
float xPadding = Scale(6.0f);
float yPadding = Scale(3.0f);
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X) + BOTTOM_X_GAP, g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
float xPadding = Scale(4);
float yPadding = Scale(3);
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X) + BOTTOM_X_GAP + Scale(1), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP)};
ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
DrawButtonContainer(min, max, 0, 0, alpha);
@@ -984,8 +1053,8 @@ static void DrawProgressBar(float progressRatio)
const uint32_t sliderColor0 = IM_COL32(57, 241, 0, 255 * alpha);
const uint32_t sliderColor1 = IM_COL32(2, 106, 0, 255 * alpha);
xPadding += Scale(1.0f);
yPadding += Scale(1.0f);
xPadding += Scale(1.5f);
yPadding += Scale(1.5f);
ImVec2 sliderMin = { min.x + xPadding, min.y + yPadding };
ImVec2 sliderMax = { max.x - xPadding, max.y - yPadding };
@@ -1177,27 +1246,23 @@ static void DrawSourcePickers()
std::list<std::filesystem::path> paths;
if (g_currentPage == WizardPage::SelectGameAndUpdate || g_currentPage == WizardPage::SelectDLC)
{
constexpr float ADD_BUTTON_MAX_TEXT_WIDTH = 160.0f;
constexpr float ADD_BUTTON_MAX_TEXT_WIDTH = 168.0f;
const std::string &addFilesText = Localise("Installer_Button_AddFiles");
float squashRatio;
ImVec2 textSize = ComputeTextSize(g_dfsogeistdFont, addFilesText.c_str(), 20.0f, squashRatio, ADD_BUTTON_MAX_TEXT_WIDTH);
textSize.x += BUTTON_TEXT_GAP;
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X + BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + BOTTOM_X_GAP + textSize.x * squashRatio), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + BOTTOM_X_GAP + textSize.x * squashRatio + BUTTON_TEXT_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
DrawButton(min, max, addFilesText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
if (buttonPressed)
{
PickerShow(false);
}
min.x += Scale(BOTTOM_X_GAP + textSize.x * squashRatio);
min.x += Scale(BOTTOM_X_GAP + textSize.x * squashRatio + BUTTON_TEXT_GAP);
const std::string &addFolderText = Localise("Installer_Button_AddFolder");
textSize = ComputeTextSize(g_dfsogeistdFont, addFolderText.c_str(), 20.0f, squashRatio, ADD_BUTTON_MAX_TEXT_WIDTH);
textSize.x += BUTTON_TEXT_GAP;
max.x = min.x + Scale(textSize.x * squashRatio);
max.x = min.x + Scale(textSize.x * squashRatio + BUTTON_TEXT_GAP);
DrawButton(min, max, addFolderText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
if (buttonPressed)
{
@@ -1227,8 +1292,9 @@ static void DrawInstallingProgress()
{
if (g_currentPage == WizardPage::Installing)
{
constexpr float ProgressSpeed = 0.1f;
float ratioTarget = g_installerProgressRatioTarget.load();
g_installerProgressRatioCurrent += (4.0f * ImGui::GetIO().DeltaTime * (ratioTarget - g_installerProgressRatioCurrent));
g_installerProgressRatioCurrent += std::min(ratioTarget - g_installerProgressRatioCurrent, ProgressSpeed * ImGui::GetIO().DeltaTime);
DrawProgressBar(g_installerProgressRatioCurrent);
if (g_installerFinished)
@@ -1243,8 +1309,14 @@ static void DrawInstallingProgress()
static void InstallerThread()
{
if (!Installer::install(g_installerSources, g_installPath, false, g_installerJournal, [&]() {
if (!Installer::install(g_installerSources, g_installPath, false, g_installerJournal, std::chrono::seconds(1), [&]() {
g_installerProgressRatioTarget = float(double(g_installerJournal.progressCounter) / double(g_installerJournal.progressTotal));
// If user is being asked for confirmation on cancelling the installation, halt the installer from progressing further.
g_installerHalted.wait(true);
// If user has confirmed they wish to cancel the installation, return false to indicate the installer should fail and stop.
return !g_installerCancelled.load();
}))
{
g_installerFailed = true;
@@ -1254,9 +1326,8 @@ static void InstallerThread()
Installer::rollback(g_installerJournal);
}
// Rest for a bit after finishing the installation, the device is tired
std::this_thread::sleep_for(std::chrono::seconds(1));
g_installerFinished = true;
g_installerCancelled = false;
}
static void InstallerStart()
@@ -1297,104 +1368,162 @@ static bool InstallerParseSources(std::string &errorMessage)
return sourcesParsed;
}
static void DrawNextButton()
static void DrawNavigationButton()
{
if (g_currentPage != WizardPage::Installing)
if (g_currentPage == WizardPage::Installing)
{
bool nextButtonEnabled = !g_isDisappearing;
if (nextButtonEnabled && g_currentPage == WizardPage::SelectGameAndUpdate)
// Navigation buttons are not offered during installation at the moment.
return;
}
bool nextButtonEnabled = !g_isDisappearing && (g_currentPage != WizardPage::Installing);
if (nextButtonEnabled && g_currentPage == WizardPage::SelectGameAndUpdate)
{
nextButtonEnabled = !g_gameSourcePath.empty() && !g_updateSourcePath.empty();
}
bool skipButton = false;
if (g_currentPage == WizardPage::SelectDLC)
{
skipButton = std::all_of(g_dlcSourcePaths.begin(), g_dlcSourcePaths.end(), [](const std::filesystem::path &path) { return path.empty(); });
}
float squashRatio;
constexpr float NAV_BUTTON_MAX_TEXT_WIDTH = 90.0f;
const char *nextButtonKey = "Installer_Button_Next";
if (skipButton)
{
nextButtonKey = "Installer_Button_Skip";
}
else if (g_currentPage == WizardPage::InstallFailed)
{
nextButtonKey = "Installer_Button_Retry";
}
const std::string &nextButtonText = Localise(nextButtonKey);
ImVec2 nextTextSize = ComputeTextSize(g_newRodinFont, nextButtonText.c_str(), 20.0f, squashRatio, NAV_BUTTON_MAX_TEXT_WIDTH);
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - nextTextSize.x * squashRatio - BOTTOM_X_GAP - BUTTON_TEXT_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
bool buttonPressed = false;
DrawButton(min, max, nextButtonText.c_str(), false, nextButtonEnabled, buttonPressed, NAV_BUTTON_MAX_TEXT_WIDTH);
if (buttonPressed)
{
XexPatcher::Result patcherResult;
if (g_currentPage == WizardPage::SelectGameAndUpdate && (patcherResult = Installer::checkGameUpdateCompatibility(g_gameSourcePath, g_updateSourcePath), patcherResult != XexPatcher::Result::Success))
{
nextButtonEnabled = !g_gameSourcePath.empty() && !g_updateSourcePath.empty();
g_currentMessagePrompt = Localise("Installer_Message_IncompatibleGameData");
g_currentMessagePromptConfirmation = false;
}
bool skipButton = false;
if (g_currentPage == WizardPage::SelectDLC)
else if (g_currentPage == WizardPage::SelectDLC)
{
skipButton = std::all_of(g_dlcSourcePaths.begin(), g_dlcSourcePaths.end(), [](const std::filesystem::path &path) { return path.empty(); });
}
float squashRatio;
constexpr float NEXT_BUTTON_MAX_TEXT_WIDTH = 100.0f;
const std::string &buttonText = Localise(skipButton ? "Installer_Button_Skip" : "Installer_Button_Next");
ImVec2 textSize = ComputeTextSize(g_newRodinFont, buttonText.c_str(), 20.0f, squashRatio, NEXT_BUTTON_MAX_TEXT_WIDTH);
textSize.x += BUTTON_TEXT_GAP;
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - textSize.x * squashRatio - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
ImVec2 max = { g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH - BOTTOM_X_GAP), g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
bool buttonPressed = false;
DrawButton(min, max, buttonText.c_str(), false, nextButtonEnabled, buttonPressed, NEXT_BUTTON_MAX_TEXT_WIDTH);
if (buttonPressed)
{
XexPatcher::Result patcherResult;
if (g_currentPage == WizardPage::SelectGameAndUpdate && (patcherResult = Installer::checkGameUpdateCompatibility(g_gameSourcePath, g_updateSourcePath), patcherResult != XexPatcher::Result::Success))
// Check if any of the DLC was not specified.
bool dlcIncomplete = false;
for (int i = 0; (i < int(DLC::Count)) && !dlcIncomplete; i++)
{
g_currentMessagePrompt = Localise("Installer_Message_IncompatibleGameData");
if (g_dlcSourcePaths[i].empty() && !g_dlcInstalled[i])
{
dlcIncomplete = true;
}
}
bool dlcInstallerMode = g_gameSourcePath.empty();
std::string sourcesErrorMessage;
if (!InstallerParseSources(sourcesErrorMessage))
{
// Some of the sources that were provided to the installer are not valid. Restart the file selection process.
std::stringstream stringStream;
stringStream << Localise("Installer_Message_InvalidFiles");
if (!sourcesErrorMessage.empty()) {
stringStream << std::endl << std::endl << sourcesErrorMessage;
}
g_currentMessagePrompt = stringStream.str();
g_currentMessagePromptConfirmation = false;
g_currentPage = dlcInstallerMode ? WizardPage::SelectDLC : WizardPage::SelectGameAndUpdate;
}
else if (g_currentPage == WizardPage::SelectDLC)
else if (dlcIncomplete && !dlcInstallerMode)
{
// Check if any of the DLC was not specified.
bool dlcIncomplete = false;
for (int i = 0; (i < int(DLC::Count)) && !dlcIncomplete; i++)
{
if (g_dlcSourcePaths[i].empty() && !g_dlcInstalled[i])
{
dlcIncomplete = true;
}
}
bool dlcInstallerMode = g_gameSourcePath.empty();
std::string sourcesErrorMessage;
if (!InstallerParseSources(sourcesErrorMessage))
{
// Some of the sources that were provided to the installer are not valid. Restart the file selection process.
std::stringstream stringStream;
stringStream << Localise("Installer_Message_InvalidFiles");
if (!sourcesErrorMessage.empty()) {
stringStream << std::endl << std::endl << sourcesErrorMessage;
}
g_currentMessagePrompt = stringStream.str();
g_currentMessagePromptConfirmation = false;
g_currentPage = dlcInstallerMode ? WizardPage::SelectDLC : WizardPage::SelectGameAndUpdate;
}
else if (dlcIncomplete && !dlcInstallerMode)
{
// Not all the DLC was specified, we show a prompt and await a confirmation before starting the installer.
g_currentMessagePrompt = Localise("Installer_Message_DLCWarning");
g_currentMessagePromptConfirmation = true;
}
else if (skipButton && dlcInstallerMode)
{
// Nothing was selected and the installer was in DLC mode, just close it.
g_isDisappearing = true;
g_disappearTime = ImGui::GetTime();
}
else
{
g_currentPage = WizardPage::CheckSpace;
}
// Not all the DLC was specified, we show a prompt and await a confirmation before starting the installer.
g_currentMessagePrompt = Localise("Installer_Message_DLCWarning");
g_currentMessagePromptSource = MessagePromptSource::Next;
g_currentMessagePromptConfirmation = true;
}
else if (g_currentPage == WizardPage::CheckSpace)
{
InstallerStart();
}
else if (g_currentPage == WizardPage::InstallSucceeded)
else if (skipButton && dlcInstallerMode)
{
// Nothing was selected and the installer was in DLC mode, just close it.
g_isDisappearing = true;
g_disappearTime = ImGui::GetTime();
}
else if (g_currentPage == WizardPage::InstallFailed)
{
g_currentPage = g_firstPage;
}
else
{
g_currentPage = WizardPage(int(g_currentPage) + 1);
g_currentPage = WizardPage::CheckSpace;
}
}
else if (g_currentPage == WizardPage::CheckSpace)
{
InstallerStart();
}
else if (g_currentPage == WizardPage::InstallSucceeded)
{
g_isDisappearing = true;
g_disappearTime = ImGui::GetTime();
}
else if (g_currentPage == WizardPage::InstallFailed)
{
g_currentPage = g_firstPage;
}
else
{
g_currentPage = WizardPage(int(g_currentPage) + 1);
}
}
}
static void CheckCancelAction()
{
if (!g_currentCursorBack)
{
return;
}
g_currentCursorBack = false;
if (g_currentPage == WizardPage::InstallSucceeded)
{
// Nothing to back out on this page.
return;
}
if (g_currentPage == WizardPage::Installing && g_installerCancelled)
{
// Installer's already been cancelled, no need for more confirmations.
return;
}
Game_PlaySound("sys_actstg_pausecansel");
if (g_currentPage == g_firstPage || g_currentPage == WizardPage::InstallFailed)
{
// Ask for confirmation if user wants to quit the installer.
g_currentMessagePrompt = Localise("Installer_Message_Quit");
g_currentMessagePromptSource = MessagePromptSource::Back;
g_currentMessagePromptConfirmation = true;
}
else if (g_currentPage == WizardPage::Installing)
{
// Ask for confirmation if the user wants to cancel the installation.
g_currentMessagePrompt = Localise("Installer_Message_Cancel");
g_currentMessagePromptSource = MessagePromptSource::Back;
g_currentMessagePromptConfirmation = true;
// Indicate to the installer that all progress should stop until the user confirms if they wish to cancel.
g_installerHalted = true;
}
else if (int(g_currentPage) > 0)
{
// Just go back to the previous page.
g_currentPage = WizardPage(int(g_currentPage) - 1);
}
}
@@ -1491,17 +1620,52 @@ static void DrawMessagePrompt()
if (messageWindowReturned)
{
if (g_currentMessagePromptConfirmation && (g_currentMessageResult == 0) && (g_currentPage == WizardPage::SelectDLC))
if (g_currentMessagePromptConfirmation && (g_currentMessageResult == 0))
{
// If user confirms the message prompt that they wish to skip installing the DLC, proceed to the next step.
g_currentPage = WizardPage::CheckSpace;
if (g_currentMessagePromptSource == MessagePromptSource::Back)
{
if (g_currentPage == WizardPage::Installing)
{
// If user confirms they wish to cancel the installation, notify the installation thread it must finish as soon as possible.
g_installerCancelled = true;
}
else
{
// In all cases, proceed to just quit the application.
g_isQuitting = true;
g_isDisappearing = true;
g_disappearTime = ImGui::GetTime();
}
}
else if (g_currentPage == WizardPage::SelectDLC)
{
// If user confirms the message prompt that they wish to skip installing the DLC, proceed to the next step.
g_currentPage = WizardPage::CheckSpace;
}
}
if (g_currentMessagePromptSource == MessagePromptSource::Back)
{
// Regardless of the confirmation, the installation thread must be resumed.
g_installerHalted = false;
g_installerHalted.notify_all();
}
g_currentMessagePrompt.clear();
g_currentMessagePromptSource = MessagePromptSource::Unknown;
g_currentMessageResult = -1;
}
}
static void PickerDrawForeground()
{
if (g_currentPickerVisible)
{
auto drawList = ImGui::GetForegroundDrawList();
drawList->AddRectFilled({ 0.0f, 0.0f }, ImGui::GetIO().DisplaySize, IM_COL32(0, 0, 0, 190));
}
}
static void PickerCheckTutorial()
{
if (!g_pickerTutorialTriggered || !g_currentMessagePrompt.empty())
@@ -1556,10 +1720,10 @@ void InstallerWizard::Init()
g_pulseInstall = LOAD_ZSTD_TEXTURE(g_pulse_install);
g_upHedgeDev = LOAD_ZSTD_TEXTURE(g_hedgedev);
for (int i = 0; i < g_creditsSize; i++)
for (int i = 0; i < g_credits.size(); i++)
{
g_creditsStr += g_credits[i];
g_creditsStr += " ";
g_creditsStr += " ";
}
}
@@ -1579,15 +1743,23 @@ void InstallerWizard::Draw()
DrawSourcePickers();
DrawSources();
DrawInstallingProgress();
DrawNextButton();
DrawNavigationButton();
CheckCancelAction();
DrawBorders();
DrawMessagePrompt();
PickerDrawForeground();
PickerCheckTutorial();
PickerCheckResults();
if (g_isDisappearing)
{
const double disappearDuration = ALL_ANIMATIONS_FULL_DURATION / 60.0;
double disappearDuration = ALL_ANIMATIONS_FULL_DURATION / 60.0;
if (g_isQuitting)
{
// Add some extra waiting time when quitting the application altogether.
disappearDuration += QUITTING_EXTRA_DURATION / 60.0;
}
if (ImGui::GetTime() > (g_disappearTime + disappearDuration))
{
s_isVisible = false;
@@ -1669,5 +1841,5 @@ bool InstallerWizard::Run(std::filesystem::path installPath, bool skipGame)
InstallerWizard::Shutdown();
EmbeddedPlayer::Shutdown();
return true;
return !g_isQuitting;
}
+40 -14
View File
@@ -22,7 +22,9 @@ static bool g_isAwaitingResult = false;
static bool g_isClosing = false;
static bool g_isControlsVisible = false;
static double g_rowSelectionTime;
static int g_selectedRowIndex;
static int g_prevSelectedRowIndex;
static int g_foregroundCount;
static bool g_upWasHeld;
@@ -46,10 +48,10 @@ int g_cancelButtonIndex;
class SDLEventListenerForMessageWindow : public SDLEventListener
{
public:
void OnSDLEvent(SDL_Event* event) override
bool OnSDLEvent(SDL_Event* event) override
{
if (App::s_isInit || !MessageWindow::s_isVisible || !hid::IsInputAllowed())
return;
return false;
constexpr float axisValueRange = 32767.0f;
constexpr float axisTapRange = 0.5f;
@@ -140,6 +142,8 @@ public:
break;
}
}
return false;
}
}
g_sdlEventListenerForMessageWindow;
@@ -208,7 +212,13 @@ void DrawButton(int rowIndex, float yOffset, float width, float height, std::str
bool isSelected = rowIndex == g_selectedRowIndex;
if (isSelected)
DrawSelectionContainer(min, max, true);
{
auto prevItemOffset = (g_prevSelectedRowIndex - g_selectedRowIndex) * height;
auto animRatio = std::clamp((ImGui::GetTime() - g_rowSelectionTime) * 60.0 / 8.0, 0.0, 1.0);
prevItemOffset *= pow(1.0 - animRatio, 3.0);
DrawSelectionContainer({ min.x, min.y + prevItemOffset }, { max.x, max.y + prevItemOffset }, true);
}
auto fontSize = Scale(28);
auto textSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, text.c_str());
@@ -292,11 +302,11 @@ void MessageWindow::Draw()
if (Config::Language == ELanguage::Japanese)
{
textMarginX -= Scale(2.5f);
textMarginY -= Scale(7.5f);
textMarginY -= Scale(2.0f);
textY += Scale(lines.size() % 2 == 0 ? 8.5f : 15.5f);
textY += Scale(lines.size() % 2 == 0 ? 1.5f : 8.0f);
}
bool isController = hid::IsInputDeviceController();
bool isKeyboard = hid::g_inputDevice == hid::EInputDevice::Keyboard;
@@ -375,6 +385,8 @@ void MessageWindow::Draw()
bool scrollUp = !g_upWasHeld && upIsHeld;
bool scrollDown = !g_downWasHeld && downIsHeld;
auto prevSelectedRowIndex = g_selectedRowIndex;
if (scrollUp)
{
--g_selectedRowIndex;
@@ -391,26 +403,34 @@ void MessageWindow::Draw()
if (scrollUp || scrollDown)
{
Game_PlaySound("sys_actstg_pausecursor");
g_rowSelectionTime = ImGui::GetTime();
g_prevSelectedRowIndex = prevSelectedRowIndex;
g_joypadAxis.y = 0;
}
g_upWasHeld = upIsHeld;
g_downWasHeld = downIsHeld;
if (isController || (isKeyboard && App::s_isInit))
auto selectIcon = EButtonIcon::A;
auto backIcon = EButtonIcon::B;
if (isController || isKeyboard)
{
if (isKeyboard && !App::s_isInit)
{
// Only display keyboard prompt during installer.
selectIcon = EButtonIcon::Enter;
backIcon = EButtonIcon::Escape;
}
std::array<Button, 2> buttons =
{
Button(Localise("Common_Select"), EButtonIcon::A),
Button(Localise("Common_Back"), EButtonIcon::B),
Button(Localise("Common_Select"), selectIcon),
Button(Localise("Common_Back"), backIcon),
};
ButtonGuide::Open(buttons);
}
else // Only display keyboard prompt during installer.
{
ButtonGuide::Open(Button(Localise("Common_Select"), EButtonIcon::Enter));
}
if (g_isDeclined)
{
@@ -448,7 +468,13 @@ void MessageWindow::Draw()
}
}
ButtonGuide::Open(Button(Localise("Common_Select"), EButtonIcon::LMB));
std::array<Button, 2> buttons =
{
Button(Localise("Common_Select"), EButtonIcon::LMB),
Button(Localise("Common_Back"), EButtonIcon::Escape),
};
ButtonGuide::Open(buttons);
}
if (g_selectedRowIndex != -1 && g_isAccepted)
+172 -27
View File
@@ -55,6 +55,8 @@ static constexpr float SETTINGS_NARROW_GRID_COUNT = 70.0f;
static constexpr float INFO_NARROW_GRID_COUNT = 34.0f;
static constexpr float PADDING_NARROW_GRID_COUNT = 1.0f;
static constexpr float INFO_TEXT_MARQUEE_DELAY = 1.2f;
static constexpr int32_t g_categoryCount = 4;
static int32_t g_categoryIndex;
static ImVec2 g_categoryAnimMin;
@@ -339,7 +341,7 @@ static float AlignToNextGrid(float value)
return round(value / GRID_SIZE) * GRID_SIZE;
}
static void DrawContainer(ImVec2 min, ImVec2 max)
static void DrawContainer(ImVec2 min, ImVec2 max, bool drawRightOutline)
{
double containerHeight = g_isStage ? 1.0 : ComputeMotion(g_appearTime, 0.0, CONTAINER_LINE_ANIMATION_DURATION);
@@ -365,10 +367,10 @@ static void DrawContainer(ImVec2 min, ImVec2 max)
SetShaderModifier(IMGUI_SHADER_MODIFIER_CHECKERBOARD);
drawList->AddRectFilled(min, { min.x + gridSize, max.y }, outerColor); // Container outline left
drawList->AddRectFilled({ max.x - gridSize, min.y }, max, outerColor); // Container outline right
drawList->AddRectFilled({ min.x + gridSize, min.y }, { max.x - gridSize, min.y + gridSize }, outerColor); // Container outline top
drawList->AddRectFilled({ min.x + gridSize, max.y - gridSize }, { max.x - gridSize, max.y }, outerColor); // Container outline bottom
drawList->AddRectFilled({ min.x, min.y + gridSize }, { min.x + gridSize, max.y - gridSize }, outerColor); // Container outline left
drawList->AddRectFilled({ max.x - gridSize, min.y + gridSize }, { max.x, max.y - gridSize }, drawRightOutline ? outerColor : innerColor); // Container outline right
drawList->AddRectFilled(min, { max.x, min.y + gridSize }, outerColor); // Container outline top
drawList->AddRectFilled({ min.x, max.y - gridSize }, max, outerColor); // Container outline bottom
drawList->AddRectFilled({ min.x + gridSize, min.y + gridSize }, { max.x - gridSize, max.y - gridSize }, innerColor); // Inner container
@@ -1104,6 +1106,10 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
valueText = fmt::format("{}x{}", GameWindow::s_width, GameWindow::s_height);
}
}
else if (config == &Config::Monitor)
{
valueText = fmt::format("{}", config->Value + 1);
}
else
{
valueText = fmt::format("{}", config->Value);
@@ -1220,7 +1226,7 @@ static void DrawConfigOptions()
DrawConfigOption(rowCount++, yOffset, &Config::MotionBlur, true);
DrawConfigOption(rowCount++, yOffset, &Config::XboxColorCorrection, true);
DrawConfigOption(rowCount++, yOffset, &Config::CutsceneAspectRatio, true);
DrawConfigOption(rowCount++, yOffset, &Config::UIScaleMode, true);
DrawConfigOption(rowCount++, yOffset, &Config::UIAlignmentMode, true);
break;
}
@@ -1239,22 +1245,62 @@ static void DrawConfigOptions()
int32_t prevSelectedRowIndex = g_selectedRowIndex;
auto time = ImGui::GetTime();
auto fastScroll = (time - g_lastTappedTime) > 0.6;
auto fastScrollSpeed = 1.0 / 3.5;
auto fastScrollEncounteredEdge = false;
static auto fastScrollSpeedUp = false;
if (scrollUp || scrollDown)
g_lastTappedTime = time;
if (!upIsHeld && !downIsHeld)
fastScrollSpeedUp = false;
if (fastScrollSpeedUp)
fastScrollSpeed /= 2;
if (fastScroll)
{
if ((time - g_lastIncrementTime) < fastScrollSpeed)
{
fastScroll = false;
}
else
{
g_lastIncrementTime = time;
scrollUp = upIsHeld;
scrollDown = downIsHeld;
}
}
if (scrollUp)
{
--g_selectedRowIndex;
if (g_selectedRowIndex < 0)
g_selectedRowIndex = rowCount - 1;
{
g_selectedRowIndex = fastScroll ? 0 : rowCount - 1;
fastScrollEncounteredEdge = fastScroll;
fastScrollSpeedUp = false;
}
}
else if (scrollDown)
{
++g_selectedRowIndex;
if (g_selectedRowIndex >= rowCount)
g_selectedRowIndex = 0;
{
g_selectedRowIndex = fastScroll ? rowCount - 1 : 0;
fastScrollEncounteredEdge = fastScroll;
fastScrollSpeedUp = false;
}
}
if (scrollUp || scrollDown)
if ((scrollUp || scrollDown) && !fastScrollEncounteredEdge)
{
g_rowSelectionTime = ImGui::GetTime();
g_rowSelectionTime = time;
g_prevSelectedRowIndex = prevSelectedRowIndex;
Game_PlaySound("sys_worldmap_cursor");
}
@@ -1270,12 +1316,18 @@ static void DrawConfigOptions()
{
g_firstVisibleRowIndex = g_selectedRowIndex;
disableMoveAnimation = true;
if (g_selectedRowIndex > 0)
fastScrollSpeedUp = true;
}
if (g_firstVisibleRowIndex + visibleRowCount - 1 < g_selectedRowIndex)
{
g_firstVisibleRowIndex = std::max(0, g_selectedRowIndex - visibleRowCount + 1);
disableMoveAnimation = true;
if (g_selectedRowIndex < rowCount - 1)
fastScrollSpeedUp = true;
}
if (disableMoveAnimation)
@@ -1310,7 +1362,7 @@ static void DrawSettingsPanel(ImVec2 settingsMin, ImVec2 settingsMax)
auto drawList = ImGui::GetForegroundDrawList();
SetProceduralOrigin(settingsMin);
DrawContainer(settingsMin, settingsMax);
DrawContainer(settingsMin, settingsMax, true);
if (DrawCategories())
{
@@ -1334,7 +1386,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
auto drawList = ImGui::GetForegroundDrawList();
SetProceduralOrigin(infoMin);
DrawContainer(infoMin, infoMax);
DrawContainer(infoMin, infoMax, false);
auto clipRectMin = drawList->GetClipRectMin();
auto clipRectMax = drawList->GetClipRectMax();
@@ -1358,7 +1410,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
}
else
{
// Specialised description for resolution scale
// Specialised description for resolution scale.
if (g_selectedItem == &Config::ResolutionScale)
{
char buf[100];
@@ -1371,54 +1423,147 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
desc = buf;
}
desc += "\n\n" + g_selectedItem->GetValueDescription(Config::Language);
const auto& valueDescription = g_selectedItem->GetValueDescription(Config::Language);
if (!valueDescription.empty())
{
desc += "\n\n" + valueDescription;
}
}
clipRectMin = { clipRectMin.x, thumbnailMax.y };
auto fontSize = Scale(28.0f);
auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
// Extra padding between the start of the description text and the bottom of the thumbnail
float offsetY = Scale(24.0f);
float textX = clipRectMin.x - Scale(0.5f);
float textY = thumbnailMax.y + offsetY;
/* Extra padding between the start
of the description text and the
bottom of the thumbnail. */
auto offsetY = Scale(24.0f);
auto textX = clipRectMin.x - Scale(0.5f);
auto textY = thumbnailMax.y + offsetY;
if (Config::Language == ELanguage::Japanese)
{
// Removing some padding of the applied due to the inclusion of annotation for Japanese
/* Removing some padding of the applied due
to the inclusion of annotation for Japanese. */
textY -= Scale(8.0f);
// The annotation (and thus the Japanese) can be drawn above the edges of the info panel thus the clip needs to be extended a bit
/* The annotation (and thus the Japanese) can be
drawn above the edges of the info panel thus the
clip needs to be extended a bit. */
clipRectMin.x -= annotationFontSize;
clipRectMin.y -= annotationFontSize;
clipRectMax.x += annotationFontSize;
clipRectMax.y += annotationFontSize;
textY += annotationFontSize;
}
auto textSize = MeasureCentredParagraph(g_seuratFont, fontSize, clipRectMax.x - clipRectMin.x, 5.0f, desc.c_str());
drawList->PushClipRect(clipRectMin, clipRectMax, false);
static auto isScrolling = false;
static auto isManualScrolling = false;
static auto scrollOffset = 0.0f;
static auto scrollTimer = 0.0f;
static auto scrollDirection = 1.0f;
auto scrollMax = textSize.y - (clipRectMax.y - textY);
auto scrollSpeed = Scale(50);
if (scrollMax > 0.0f)
{
if (auto pInputState = SWA::CInputState::GetInstance())
{
auto& rPadState = pInputState->GetPadState();
auto& vert = rPadState.RightStickVertical;
if (fabs(vert) > 0.25f)
{
isManualScrolling = true;
scrollOffset += vert * scrollSpeed * App::s_deltaTime;
}
else if (isManualScrolling && fabs(vert) <= 0.25f)
{
isScrolling = false;
isManualScrolling = false;
scrollTimer = 0.0f;
scrollDirection = vert > 0.0f ? 1.0f : -1.0f;
}
}
if (!isManualScrolling)
{
if (!isScrolling)
{
scrollTimer += App::s_deltaTime;
if (scrollTimer >= INFO_TEXT_MARQUEE_DELAY)
isScrolling = true;
}
if (isScrolling)
{
scrollOffset += scrollSpeed * scrollDirection * App::s_deltaTime;
if (scrollOffset >= scrollMax)
{
isScrolling = false;
scrollOffset = scrollMax;
scrollTimer = 0.0f;
scrollDirection = -1.0f;
}
else if (scrollOffset <= 0.0f)
{
isScrolling = false;
scrollOffset = 0;
scrollTimer = 0.0f;
scrollDirection = 1.0f;
}
}
}
scrollOffset = std::clamp(scrollOffset, 0.0f, scrollMax);
}
else
{
isScrolling = false;
scrollOffset = 0.0f;
scrollTimer = 0.0f;
scrollDirection = 1.0f;
}
SetVerticalMarqueeFade(clipRectMin, clipRectMax, Scale(24), Lerp(Scale(24), 0.0f, scrollOffset / scrollMax));
DrawRubyAnnotatedText
(
g_seuratFont,
fontSize,
clipRectMax.x - clipRectMin.x,
{ textX, textY },
{ textX, textY - scrollOffset },
5.0f,
desc.c_str(),
[=](const char* str, ImVec2 pos)
{
DrawTextBasic(g_seuratFont, fontSize, pos, IM_COL32(255, 255, 255, 255), str);
DrawTextBasic(g_seuratFont, fontSize, pos, IM_COL32_WHITE, str);
},
[=](const char* str, float size, ImVec2 pos)
{
DrawTextBasic(g_seuratFont, size, pos, IM_COL32(255, 255, 255, 255), str);
DrawTextBasic(g_seuratFont, size, pos, IM_COL32_WHITE, str);
}
);
ResetMarqueeFade();
drawList->PopClipRect();
// Reset parameters on new selected row.
if (ImGui::GetTime() - g_rowSelectionTime <= 0.0f)
{
isScrolling = false;
scrollOffset = 0.0f;
scrollTimer = 0.0f;
scrollDirection = 1.0f;
}
}
ResetProceduralOrigin();
@@ -39,7 +39,7 @@
#include <res/images/options_menu/thumbnails/time_of_day_transition_playstation.dds.h>
#include <res/images/options_menu/thumbnails/transparency_antialiasing_false.dds.h>
#include <res/images/options_menu/thumbnails/transparency_antialiasing_true.dds.h>
#include <res/images/options_menu/thumbnails/ui_scale_mode.dds.h>
#include <res/images/options_menu/thumbnails/ui_alignment_mode.dds.h>
#include <res/images/options_menu/thumbnails/vertical_camera.dds.h>
#include <res/images/options_menu/thumbnails/voice_language.dds.h>
#include <res/images/options_menu/thumbnails/vibration.dds.h>
@@ -112,7 +112,7 @@ void LoadThumbnails()
g_motionBlurThumbnails[EMotionBlur::Enhanced] = LOAD_ZSTD_TEXTURE(g_motion_blur_enhanced);
g_configThumbnails[&Config::XboxColorCorrection] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction);
g_configThumbnails[&Config::UIScaleMode] = LOAD_ZSTD_TEXTURE(g_ui_scale_mode);
g_configThumbnails[&Config::UIAlignmentMode] = LOAD_ZSTD_TEXTURE(g_ui_alignment_mode);
}
template<typename T>
+21 -1
View File
@@ -67,9 +67,29 @@ void AchievementManager::Unlock(uint16_t id)
AchievementOverlay::Open(id);
}
void AchievementManager::Load()
void AchievementManager::UnlockAll()
{
for (uint16_t i = 24; i <= 83; i++)
{
if (i == 30)
i = 31;
if (i == 55)
i = 64;
AchievementManager::Unlock(i);
}
}
void AchievementManager::Reset()
{
Data = {};
}
void AchievementManager::Load()
{
AchievementManager::Reset();
Status = EAchStatus::Success;
auto dataPath = GetDataPath(true);
@@ -27,6 +27,8 @@ public:
static size_t GetTotalRecords();
static bool IsUnlocked(uint16_t id);
static void Unlock(uint16_t id);
static void UnlockAll();
static void Reset();
static void Load();
static void Save(bool ignoreStatus = false);
};
+140 -140
View File
@@ -39,7 +39,7 @@ CONFIG_DEFINE_ENUM_TEMPLATE(EControllerIcons)
CONFIG_DEFINE_ENUM_TEMPLATE(SDL_Scancode)
{
{ "UNKNOWN", SDL_SCANCODE_UNKNOWN },
{ "???", SDL_SCANCODE_UNKNOWN },
{ "A", SDL_SCANCODE_A },
{ "B", SDL_SCANCODE_B },
{ "C", SDL_SCANCODE_C },
@@ -83,17 +83,17 @@ CONFIG_DEFINE_ENUM_TEMPLATE(SDL_Scancode)
{ "SPACE", SDL_SCANCODE_SPACE },
{ "MINUS", SDL_SCANCODE_MINUS },
{ "EQUALS", SDL_SCANCODE_EQUALS },
{ "LEFTBRACKET", SDL_SCANCODE_LEFTBRACKET },
{ "RIGHTBRACKET", SDL_SCANCODE_RIGHTBRACKET },
{ "LEFT BRACKET", SDL_SCANCODE_LEFTBRACKET },
{ "RIGHT BRACKET", SDL_SCANCODE_RIGHTBRACKET },
{ "BACKSLASH", SDL_SCANCODE_BACKSLASH },
{ "NONUSHASH", SDL_SCANCODE_NONUSHASH },
{ "NON-US HASH", SDL_SCANCODE_NONUSHASH },
{ "SEMICOLON", SDL_SCANCODE_SEMICOLON },
{ "APOSTROPHE", SDL_SCANCODE_APOSTROPHE },
{ "GRAVE", SDL_SCANCODE_GRAVE },
{ "COMMA", SDL_SCANCODE_COMMA },
{ "PERIOD", SDL_SCANCODE_PERIOD },
{ "SLASH", SDL_SCANCODE_SLASH },
{ "CAPSLOCK", SDL_SCANCODE_CAPSLOCK },
{ "CAPS LOCK", SDL_SCANCODE_CAPSLOCK },
{ "F1", SDL_SCANCODE_F1 },
{ "F2", SDL_SCANCODE_F2 },
{ "F3", SDL_SCANCODE_F3 },
@@ -106,40 +106,40 @@ CONFIG_DEFINE_ENUM_TEMPLATE(SDL_Scancode)
{ "F10", SDL_SCANCODE_F10 },
{ "F11", SDL_SCANCODE_F11 },
{ "F12", SDL_SCANCODE_F12 },
{ "PRINTSCREEN", SDL_SCANCODE_PRINTSCREEN },
{ "SCROLLLOCK", SDL_SCANCODE_SCROLLLOCK },
{ "PRINT SCREEN", SDL_SCANCODE_PRINTSCREEN },
{ "SCROLL LOCK", SDL_SCANCODE_SCROLLLOCK },
{ "PAUSE", SDL_SCANCODE_PAUSE },
{ "INSERT", SDL_SCANCODE_INSERT },
{ "HOME", SDL_SCANCODE_HOME },
{ "PAGEUP", SDL_SCANCODE_PAGEUP },
{ "PAGE UP", SDL_SCANCODE_PAGEUP },
{ "DELETE", SDL_SCANCODE_DELETE },
{ "END", SDL_SCANCODE_END },
{ "PAGEDOWN", SDL_SCANCODE_PAGEDOWN },
{ "PAGE DOWN", SDL_SCANCODE_PAGEDOWN },
{ "RIGHT", SDL_SCANCODE_RIGHT },
{ "LEFT", SDL_SCANCODE_LEFT },
{ "DOWN", SDL_SCANCODE_DOWN },
{ "UP", SDL_SCANCODE_UP },
{ "NUMLOCKCLEAR", SDL_SCANCODE_NUMLOCKCLEAR },
{ "KP_DIVIDE", SDL_SCANCODE_KP_DIVIDE },
{ "KP_MULTIPLY", SDL_SCANCODE_KP_MULTIPLY },
{ "KP_MINUS", SDL_SCANCODE_KP_MINUS },
{ "KP_PLUS", SDL_SCANCODE_KP_PLUS },
{ "KP_ENTER", SDL_SCANCODE_KP_ENTER },
{ "KP_1", SDL_SCANCODE_KP_1 },
{ "KP_2", SDL_SCANCODE_KP_2 },
{ "KP_3", SDL_SCANCODE_KP_3 },
{ "KP_4", SDL_SCANCODE_KP_4 },
{ "KP_5", SDL_SCANCODE_KP_5 },
{ "KP_6", SDL_SCANCODE_KP_6 },
{ "KP_7", SDL_SCANCODE_KP_7 },
{ "KP_8", SDL_SCANCODE_KP_8 },
{ "KP_9", SDL_SCANCODE_KP_9 },
{ "KP_0", SDL_SCANCODE_KP_0 },
{ "KP_PERIOD", SDL_SCANCODE_KP_PERIOD },
{ "NONUSBACKSLASH", SDL_SCANCODE_NONUSBACKSLASH },
{ "NUM LOCK", SDL_SCANCODE_NUMLOCKCLEAR },
{ "KP DIVIDE", SDL_SCANCODE_KP_DIVIDE },
{ "KP MULTIPLY", SDL_SCANCODE_KP_MULTIPLY },
{ "KP MINUS", SDL_SCANCODE_KP_MINUS },
{ "KP PLUS", SDL_SCANCODE_KP_PLUS },
{ "KP ENTER", SDL_SCANCODE_KP_ENTER },
{ "KP 1", SDL_SCANCODE_KP_1 },
{ "KP 2", SDL_SCANCODE_KP_2 },
{ "KP 3", SDL_SCANCODE_KP_3 },
{ "KP 4", SDL_SCANCODE_KP_4 },
{ "KP 5", SDL_SCANCODE_KP_5 },
{ "KP 6", SDL_SCANCODE_KP_6 },
{ "KP 7", SDL_SCANCODE_KP_7 },
{ "KP 8", SDL_SCANCODE_KP_8 },
{ "KP 9", SDL_SCANCODE_KP_9 },
{ "KP 0", SDL_SCANCODE_KP_0 },
{ "KP PERIOD", SDL_SCANCODE_KP_PERIOD },
{ "NON-US BACKSLASH", SDL_SCANCODE_NONUSBACKSLASH },
{ "APPLICATION", SDL_SCANCODE_APPLICATION },
{ "POWER", SDL_SCANCODE_POWER },
{ "KP_EQUALS", SDL_SCANCODE_KP_EQUALS },
{ "KP EQUALS", SDL_SCANCODE_KP_EQUALS },
{ "F13", SDL_SCANCODE_F13 },
{ "F14", SDL_SCANCODE_F14 },
{ "F15", SDL_SCANCODE_F15 },
@@ -164,128 +164,128 @@ CONFIG_DEFINE_ENUM_TEMPLATE(SDL_Scancode)
{ "PASTE", SDL_SCANCODE_PASTE },
{ "FIND", SDL_SCANCODE_FIND },
{ "MUTE", SDL_SCANCODE_MUTE },
{ "VOLUMEUP", SDL_SCANCODE_VOLUMEUP },
{ "VOLUMEDOWN", SDL_SCANCODE_VOLUMEDOWN },
{ "KP_COMMA", SDL_SCANCODE_KP_COMMA },
{ "KP_EQUALSAS400", SDL_SCANCODE_KP_EQUALSAS400 },
{ "INTERNATIONAL1", SDL_SCANCODE_INTERNATIONAL1 },
{ "INTERNATIONAL2", SDL_SCANCODE_INTERNATIONAL2 },
{ "INTERNATIONAL3", SDL_SCANCODE_INTERNATIONAL3 },
{ "INTERNATIONAL4", SDL_SCANCODE_INTERNATIONAL4 },
{ "INTERNATIONAL5", SDL_SCANCODE_INTERNATIONAL5 },
{ "INTERNATIONAL6", SDL_SCANCODE_INTERNATIONAL6 },
{ "INTERNATIONAL7", SDL_SCANCODE_INTERNATIONAL7 },
{ "INTERNATIONAL8", SDL_SCANCODE_INTERNATIONAL8 },
{ "INTERNATIONAL9", SDL_SCANCODE_INTERNATIONAL9 },
{ "LANG1", SDL_SCANCODE_LANG1 },
{ "LANG2", SDL_SCANCODE_LANG2 },
{ "LANG3", SDL_SCANCODE_LANG3 },
{ "LANG4", SDL_SCANCODE_LANG4 },
{ "LANG5", SDL_SCANCODE_LANG5 },
{ "LANG6", SDL_SCANCODE_LANG6 },
{ "LANG7", SDL_SCANCODE_LANG7 },
{ "LANG8", SDL_SCANCODE_LANG8 },
{ "LANG9", SDL_SCANCODE_LANG9 },
{ "ALTERASE", SDL_SCANCODE_ALTERASE },
{ "SYSREQ", SDL_SCANCODE_SYSREQ },
{ "VOLUME UP", SDL_SCANCODE_VOLUMEUP },
{ "VOLUME DOWN", SDL_SCANCODE_VOLUMEDOWN },
{ "KP COMMA", SDL_SCANCODE_KP_COMMA },
{ "KP EQUALS AS400", SDL_SCANCODE_KP_EQUALSAS400 },
{ "INTERNATIONAL 1", SDL_SCANCODE_INTERNATIONAL1 },
{ "INTERNATIONAL 2", SDL_SCANCODE_INTERNATIONAL2 },
{ "INTERNATIONAL 3", SDL_SCANCODE_INTERNATIONAL3 },
{ "INTERNATIONAL 4", SDL_SCANCODE_INTERNATIONAL4 },
{ "INTERNATIONAL 5", SDL_SCANCODE_INTERNATIONAL5 },
{ "INTERNATIONAL 6", SDL_SCANCODE_INTERNATIONAL6 },
{ "INTERNATIONAL 7", SDL_SCANCODE_INTERNATIONAL7 },
{ "INTERNATIONAL 8", SDL_SCANCODE_INTERNATIONAL8 },
{ "INTERNATIONAL 9", SDL_SCANCODE_INTERNATIONAL9 },
{ "LANG 1", SDL_SCANCODE_LANG1 },
{ "LANG 2", SDL_SCANCODE_LANG2 },
{ "LANG 3", SDL_SCANCODE_LANG3 },
{ "LANG 4", SDL_SCANCODE_LANG4 },
{ "LANG 5", SDL_SCANCODE_LANG5 },
{ "LANG 6", SDL_SCANCODE_LANG6 },
{ "LANG 7", SDL_SCANCODE_LANG7 },
{ "LANG 8", SDL_SCANCODE_LANG8 },
{ "LANG 9", SDL_SCANCODE_LANG9 },
{ "ALT ERASE", SDL_SCANCODE_ALTERASE },
{ "SYS REQ", SDL_SCANCODE_SYSREQ },
{ "CANCEL", SDL_SCANCODE_CANCEL },
{ "CLEAR", SDL_SCANCODE_CLEAR },
{ "PRIOR", SDL_SCANCODE_PRIOR },
{ "RETURN2", SDL_SCANCODE_RETURN2 },
{ "RETURN 2", SDL_SCANCODE_RETURN2 },
{ "SEPARATOR", SDL_SCANCODE_SEPARATOR },
{ "OUT", SDL_SCANCODE_OUT },
{ "OPER", SDL_SCANCODE_OPER },
{ "CLEARAGAIN", SDL_SCANCODE_CLEARAGAIN },
{ "CRSEL", SDL_SCANCODE_CRSEL },
{ "EXSEL", SDL_SCANCODE_EXSEL },
{ "KP_00", SDL_SCANCODE_KP_00 },
{ "KP_000", SDL_SCANCODE_KP_000 },
{ "THOUSANDSSEPARATOR", SDL_SCANCODE_THOUSANDSSEPARATOR },
{ "DECIMALSEPARATOR", SDL_SCANCODE_DECIMALSEPARATOR },
{ "CURRENCYUNIT", SDL_SCANCODE_CURRENCYUNIT },
{ "CURRENCYSUBUNIT", SDL_SCANCODE_CURRENCYSUBUNIT },
{ "KP_LEFTPAREN", SDL_SCANCODE_KP_LEFTPAREN },
{ "KP_RIGHTPAREN", SDL_SCANCODE_KP_RIGHTPAREN },
{ "KP_LEFTBRACE", SDL_SCANCODE_KP_LEFTBRACE },
{ "KP_RIGHTBRACE", SDL_SCANCODE_KP_RIGHTBRACE },
{ "KP_TAB", SDL_SCANCODE_KP_TAB },
{ "KP_BACKSPACE", SDL_SCANCODE_KP_BACKSPACE },
{ "KP_A", SDL_SCANCODE_KP_A },
{ "KP_B", SDL_SCANCODE_KP_B },
{ "KP_C", SDL_SCANCODE_KP_C },
{ "KP_D", SDL_SCANCODE_KP_D },
{ "KP_E", SDL_SCANCODE_KP_E },
{ "KP_F", SDL_SCANCODE_KP_F },
{ "KP_XOR", SDL_SCANCODE_KP_XOR },
{ "KP_POWER", SDL_SCANCODE_KP_POWER },
{ "KP_PERCENT", SDL_SCANCODE_KP_PERCENT },
{ "KP_LESS", SDL_SCANCODE_KP_LESS },
{ "KP_GREATER", SDL_SCANCODE_KP_GREATER },
{ "KP_AMPERSAND", SDL_SCANCODE_KP_AMPERSAND },
{ "KP_DBLAMPERSAND", SDL_SCANCODE_KP_DBLAMPERSAND },
{ "KP_VERTICALBAR", SDL_SCANCODE_KP_VERTICALBAR },
{ "KP_DBLVERTICALBAR", SDL_SCANCODE_KP_DBLVERTICALBAR },
{ "KP_COLON", SDL_SCANCODE_KP_COLON },
{ "KP_HASH", SDL_SCANCODE_KP_HASH },
{ "KP_SPACE", SDL_SCANCODE_KP_SPACE },
{ "KP_AT", SDL_SCANCODE_KP_AT },
{ "KP_EXCLAM", SDL_SCANCODE_KP_EXCLAM },
{ "KP_MEMSTORE", SDL_SCANCODE_KP_MEMSTORE },
{ "KP_MEMRECALL", SDL_SCANCODE_KP_MEMRECALL },
{ "KP_MEMCLEAR", SDL_SCANCODE_KP_MEMCLEAR },
{ "KP_MEMADD", SDL_SCANCODE_KP_MEMADD },
{ "KP_MEMSUBTRACT", SDL_SCANCODE_KP_MEMSUBTRACT },
{ "KP_MEMMULTIPLY", SDL_SCANCODE_KP_MEMMULTIPLY },
{ "KP_MEMDIVIDE", SDL_SCANCODE_KP_MEMDIVIDE },
{ "KP_PLUSMINUS", SDL_SCANCODE_KP_PLUSMINUS },
{ "KP_CLEAR", SDL_SCANCODE_KP_CLEAR },
{ "KP_CLEARENTRY", SDL_SCANCODE_KP_CLEARENTRY },
{ "KP_BINARY", SDL_SCANCODE_KP_BINARY },
{ "KP_OCTAL", SDL_SCANCODE_KP_OCTAL },
{ "KP_DECIMAL", SDL_SCANCODE_KP_DECIMAL },
{ "KP_HEXADECIMAL", SDL_SCANCODE_KP_HEXADECIMAL },
{ "LCTRL", SDL_SCANCODE_LCTRL },
{ "LSHIFT", SDL_SCANCODE_LSHIFT },
{ "LALT", SDL_SCANCODE_LALT },
{ "LGUI", SDL_SCANCODE_LGUI },
{ "RCTRL", SDL_SCANCODE_RCTRL },
{ "RSHIFT", SDL_SCANCODE_RSHIFT },
{ "RALT", SDL_SCANCODE_RALT },
{ "RGUI", SDL_SCANCODE_RGUI },
{ "CLEAR AGAIN", SDL_SCANCODE_CLEARAGAIN },
{ "CR SEL", SDL_SCANCODE_CRSEL },
{ "EX SEL", SDL_SCANCODE_EXSEL },
{ "KP 00", SDL_SCANCODE_KP_00 },
{ "KP 000", SDL_SCANCODE_KP_000 },
{ "THOUSANDS SEPARATOR", SDL_SCANCODE_THOUSANDSSEPARATOR },
{ "DECIMAL SEPARATOR", SDL_SCANCODE_DECIMALSEPARATOR },
{ "CURRENCY UNIT", SDL_SCANCODE_CURRENCYUNIT },
{ "CURRENCY SUBUNIT", SDL_SCANCODE_CURRENCYSUBUNIT },
{ "KP LEFT PAREN", SDL_SCANCODE_KP_LEFTPAREN },
{ "KP RIGHT PAREN", SDL_SCANCODE_KP_RIGHTPAREN },
{ "KP LEFT BRACE", SDL_SCANCODE_KP_LEFTBRACE },
{ "KP RIGHT BRACE", SDL_SCANCODE_KP_RIGHTBRACE },
{ "KP TAB", SDL_SCANCODE_KP_TAB },
{ "KP BACKSPACE", SDL_SCANCODE_KP_BACKSPACE },
{ "KP A", SDL_SCANCODE_KP_A },
{ "KP B", SDL_SCANCODE_KP_B },
{ "KP C", SDL_SCANCODE_KP_C },
{ "KP D", SDL_SCANCODE_KP_D },
{ "KP E", SDL_SCANCODE_KP_E },
{ "KP F", SDL_SCANCODE_KP_F },
{ "KP XOR", SDL_SCANCODE_KP_XOR },
{ "KP POWER", SDL_SCANCODE_KP_POWER },
{ "KP PERCENT", SDL_SCANCODE_KP_PERCENT },
{ "KP LESS", SDL_SCANCODE_KP_LESS },
{ "KP GREATER", SDL_SCANCODE_KP_GREATER },
{ "KP AMPERSAND", SDL_SCANCODE_KP_AMPERSAND },
{ "KP DBL AMPERSAND", SDL_SCANCODE_KP_DBLAMPERSAND },
{ "KP VERTICAL BAR", SDL_SCANCODE_KP_VERTICALBAR },
{ "KP DBL VERTICAL BAR", SDL_SCANCODE_KP_DBLVERTICALBAR },
{ "KP COLON", SDL_SCANCODE_KP_COLON },
{ "KP HASH", SDL_SCANCODE_KP_HASH },
{ "KP SPACE", SDL_SCANCODE_KP_SPACE },
{ "KP AT", SDL_SCANCODE_KP_AT },
{ "KP EXCLAM", SDL_SCANCODE_KP_EXCLAM },
{ "KP MEM STORE", SDL_SCANCODE_KP_MEMSTORE },
{ "KP MEM RECALL", SDL_SCANCODE_KP_MEMRECALL },
{ "KP MEM CLEAR", SDL_SCANCODE_KP_MEMCLEAR },
{ "KP MEM ADD", SDL_SCANCODE_KP_MEMADD },
{ "KP MEM SUBTRACT", SDL_SCANCODE_KP_MEMSUBTRACT },
{ "KP MEM MULTIPLY", SDL_SCANCODE_KP_MEMMULTIPLY },
{ "KP MEM DIVIDE", SDL_SCANCODE_KP_MEMDIVIDE },
{ "KP PLUS/MINUS", SDL_SCANCODE_KP_PLUSMINUS },
{ "KP CLEAR", SDL_SCANCODE_KP_CLEAR },
{ "KP CLEAR ENTRY", SDL_SCANCODE_KP_CLEARENTRY },
{ "KP BINARY", SDL_SCANCODE_KP_BINARY },
{ "KP OCTAL", SDL_SCANCODE_KP_OCTAL },
{ "KP DECIMAL", SDL_SCANCODE_KP_DECIMAL },
{ "KP HEXADECIMAL", SDL_SCANCODE_KP_HEXADECIMAL },
{ "LEFT CTRL", SDL_SCANCODE_LCTRL },
{ "LEFT SHIFT", SDL_SCANCODE_LSHIFT },
{ "LEFT ALT", SDL_SCANCODE_LALT },
{ "LEFT SUPER", SDL_SCANCODE_LGUI },
{ "RIGHT CTRL", SDL_SCANCODE_RCTRL },
{ "RIGHT SHIFT", SDL_SCANCODE_RSHIFT },
{ "RIGHT ALT", SDL_SCANCODE_RALT },
{ "RIGHT SUPER", SDL_SCANCODE_RGUI },
{ "MODE", SDL_SCANCODE_MODE },
{ "AUDIONEXT", SDL_SCANCODE_AUDIONEXT },
{ "AUDIOPREV", SDL_SCANCODE_AUDIOPREV },
{ "AUDIOSTOP", SDL_SCANCODE_AUDIOSTOP },
{ "AUDIOPLAY", SDL_SCANCODE_AUDIOPLAY },
{ "AUDIOMUTE", SDL_SCANCODE_AUDIOMUTE },
{ "MEDIASELECT", SDL_SCANCODE_MEDIASELECT },
{ "AUDIO NEXT", SDL_SCANCODE_AUDIONEXT },
{ "AUDIO PREV", SDL_SCANCODE_AUDIOPREV },
{ "AUDIO STOP", SDL_SCANCODE_AUDIOSTOP },
{ "AUDIO PLAY", SDL_SCANCODE_AUDIOPLAY },
{ "AUDIO MUTE", SDL_SCANCODE_AUDIOMUTE },
{ "MEDIA SELECT", SDL_SCANCODE_MEDIASELECT },
{ "WWW", SDL_SCANCODE_WWW },
{ "MAIL", SDL_SCANCODE_MAIL },
{ "CALCULATOR", SDL_SCANCODE_CALCULATOR },
{ "COMPUTER", SDL_SCANCODE_COMPUTER },
{ "AC_SEARCH", SDL_SCANCODE_AC_SEARCH },
{ "AC_HOME", SDL_SCANCODE_AC_HOME },
{ "AC_BACK", SDL_SCANCODE_AC_BACK },
{ "AC_FORWARD", SDL_SCANCODE_AC_FORWARD },
{ "AC_STOP", SDL_SCANCODE_AC_STOP },
{ "AC_REFRESH", SDL_SCANCODE_AC_REFRESH },
{ "AC_BOOKMARKS", SDL_SCANCODE_AC_BOOKMARKS },
{ "BRIGHTNESSDOWN", SDL_SCANCODE_BRIGHTNESSDOWN },
{ "BRIGHTNESSUP", SDL_SCANCODE_BRIGHTNESSUP },
{ "DISPLAYSWITCH", SDL_SCANCODE_DISPLAYSWITCH },
{ "KBDILLUMTOGGLE", SDL_SCANCODE_KBDILLUMTOGGLE },
{ "KBDILLUMDOWN", SDL_SCANCODE_KBDILLUMDOWN },
{ "KBDILLUMUP", SDL_SCANCODE_KBDILLUMUP },
{ "AC SEARCH", SDL_SCANCODE_AC_SEARCH },
{ "AC HOME", SDL_SCANCODE_AC_HOME },
{ "AC BACK", SDL_SCANCODE_AC_BACK },
{ "AC FORWARD", SDL_SCANCODE_AC_FORWARD },
{ "AC STOP", SDL_SCANCODE_AC_STOP },
{ "AC REFRESH", SDL_SCANCODE_AC_REFRESH },
{ "AC BOOKMARKS", SDL_SCANCODE_AC_BOOKMARKS },
{ "BRIGHTNESS DOWN", SDL_SCANCODE_BRIGHTNESSDOWN },
{ "BRIGHTNESS UP", SDL_SCANCODE_BRIGHTNESSUP },
{ "DISPLAY SWITCH", SDL_SCANCODE_DISPLAYSWITCH },
{ "KBD ILLUM TOGGLE", SDL_SCANCODE_KBDILLUMTOGGLE },
{ "KBD ILLUM DOWN", SDL_SCANCODE_KBDILLUMDOWN },
{ "KBD ILLUM UP", SDL_SCANCODE_KBDILLUMUP },
{ "EJECT", SDL_SCANCODE_EJECT },
{ "SLEEP", SDL_SCANCODE_SLEEP },
{ "APP1", SDL_SCANCODE_APP1 },
{ "APP2", SDL_SCANCODE_APP2 },
{ "AUDIOREWIND", SDL_SCANCODE_AUDIOREWIND },
{ "AUDIOFASTFORWARD", SDL_SCANCODE_AUDIOFASTFORWARD },
{ "SOFTLEFT", SDL_SCANCODE_SOFTLEFT },
{ "SOFTRIGHT", SDL_SCANCODE_SOFTRIGHT },
{ "APP 1", SDL_SCANCODE_APP1 },
{ "APP 2", SDL_SCANCODE_APP2 },
{ "AUDIO REWIND", SDL_SCANCODE_AUDIOREWIND },
{ "AUDIO FAST FORWARD", SDL_SCANCODE_AUDIOFASTFORWARD },
{ "SOFT LEFT", SDL_SCANCODE_SOFTLEFT },
{ "SOFT RIGHT", SDL_SCANCODE_SOFTRIGHT },
{ "CALL", SDL_SCANCODE_CALL },
{ "ENDCALL", SDL_SCANCODE_ENDCALL },
{ "END CALL", SDL_SCANCODE_ENDCALL },
};
CONFIG_DEFINE_ENUM_TEMPLATE(EChannelConfiguration)
@@ -376,11 +376,11 @@ CONFIG_DEFINE_ENUM_TEMPLATE(ECutsceneAspectRatio)
{ "Unlocked", ECutsceneAspectRatio::Unlocked }
};
CONFIG_DEFINE_ENUM_TEMPLATE(EUIScaleMode)
CONFIG_DEFINE_ENUM_TEMPLATE(EUIAlignmentMode)
{
{ "Edge", EUIScaleMode::Edge },
{ "Centre", EUIScaleMode::Centre },
{ "Center", EUIScaleMode::Centre }
{ "Edge", EUIAlignmentMode::Edge },
{ "Centre", EUIAlignmentMode::Centre },
{ "Center", EUIAlignmentMode::Centre }
};
#undef CONFIG_DEFINE
+1 -1
View File
@@ -138,7 +138,7 @@ enum class ECutsceneAspectRatio : uint32_t
Unlocked
};
enum class EUIScaleMode : uint32_t
enum class EUIAlignmentMode : uint32_t
{
Edge,
Centre
+1 -1
View File
@@ -96,7 +96,7 @@ CONFIG_DEFINE_ENUM("Video", EDepthOfFieldQuality, DepthOfFieldQuality, EDepthOfF
CONFIG_DEFINE_ENUM_LOCALISED("Video", EMotionBlur, MotionBlur, EMotionBlur::Original);
CONFIG_DEFINE_LOCALISED("Video", bool, XboxColorCorrection, false);
CONFIG_DEFINE_ENUM_LOCALISED("Video", ECutsceneAspectRatio, CutsceneAspectRatio, ECutsceneAspectRatio::Original);
CONFIG_DEFINE_ENUM_LOCALISED("Video", EUIScaleMode, UIScaleMode, EUIScaleMode::Edge);
CONFIG_DEFINE_ENUM_LOCALISED("Video", EUIAlignmentMode, UIAlignmentMode, EUIAlignmentMode::Edge);
CONFIG_DEFINE_HIDDEN("Exports", bool, AllowCancellingUnleash, false);
CONFIG_DEFINE_HIDDEN("Exports", bool, DisableAutoSaveWarning, false);
-6
View File
@@ -1,12 +1,6 @@
#include "registry.h"
#include <os/process.h>
#include <os/registry.h>
#include <user/config.h>
void Registry::Load()
{
}
void Registry::Save()
{
-1
View File
@@ -3,6 +3,5 @@
class Registry
{
public:
static void Load();
static void Save();
};
+43
View File
@@ -914,3 +914,46 @@ jump_address = 0x82AE2774
name = "ApplicationFrameLimiterMidAsmHook"
address = 0x822C1064
jump_address = 0x822C111C
[[midasm_hook]]
name = "PressStartSaveLoadThreadMidAsmHook"
address = 0x822C4358
[[midasm_hook]]
name = "FxShadowMapInitMidAsmHook"
address = 0x82BAD8F4
registers = ["r11"]
[[midasm_hook]]
name = "FxShadowMapNoTerrainMidAsmHook"
address = 0x82BAD9EC
registers = ["r4", "r30"]
after_instruction = true
[[midasm_hook]]
name = "FxShadowMapMidAsmHook"
address = 0x82BADADC
registers = ["r4", "r5", "r6", "r30"]
jump_address_on_true = 0x82BAD9F0
jump_address_on_false = 0x82BADAFC
[[midasm_hook]]
name = "CExStageBossCStateBattleAllocMidAsmHook"
address = 0x82B026DC
registers = ["r3"]
after_instruction = true
[[midasm_hook]]
name = "CExStageBossCStateBattleCtorMidAsmHook"
address = 0x82B026E4
registers = ["r3"]
[[midasm_hook]]
name = "EvilHudGuideAllocMidAsmHook"
address = 0x823B6908
registers = ["r3"]
[[midasm_hook]]
name = "EvilHudGuideUpdateMidAsmHook"
address = 0x82449800
registers = ["r30", "f30"]