mirror of
https://github.com/hedge-dev/UnleashedRecomp
synced 2026-06-10 12:55:51 -04:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d696524dbf | |||
| e3ac47a797 | |||
| 72640c8749 | |||
| 1687c65be9 | |||
| 6dac017d00 | |||
| 2150faed2e | |||
| 2f1b98c570 | |||
| 70ebdaa685 | |||
| e1edd5f35d | |||
| 88df0e08b7 | |||
| 511c670def | |||
| 16c35b45c2 | |||
| b291bdba91 | |||
| 727be2b47c | |||
| 62ad3a1a13 | |||
| 6c8dbdb6bc | |||
| 71bb081645 | |||
| 871515b3be | |||
| 266d436c28 | |||
| e7cc5a858e | |||
| 9549ba54aa | |||
| 47b1f20679 | |||
| ef51f04d4f | |||
| b68dbec612 | |||
| 96108e1759 | |||
| d3589979e4 | |||
| 2db4a9c78c | |||
| 2d56566924 | |||
| 553e011dad | |||
| 900ba7c916 | |||
| 66648d550a | |||
| c40ffbc70d | |||
| ee97736d58 | |||
| bbb3ebc25d | |||
| 52558a674e | |||
| 11d0fd2f9c |
@@ -150,6 +150,7 @@ set(UNLEASHED_RECOMP_PATCHES_CXX_SOURCES
|
|||||||
set(UNLEASHED_RECOMP_UI_CXX_SOURCES
|
set(UNLEASHED_RECOMP_UI_CXX_SOURCES
|
||||||
"ui/achievement_menu.cpp"
|
"ui/achievement_menu.cpp"
|
||||||
"ui/achievement_overlay.cpp"
|
"ui/achievement_overlay.cpp"
|
||||||
|
"ui/black_bar.cpp"
|
||||||
"ui/button_guide.cpp"
|
"ui/button_guide.cpp"
|
||||||
"ui/fader.cpp"
|
"ui/fader.cpp"
|
||||||
"ui/game_window.cpp"
|
"ui/game_window.cpp"
|
||||||
@@ -351,9 +352,11 @@ file(CHMOD ${DIRECTX_DXC_TOOL} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
|
|||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_libraries(UnleashedRecomp PRIVATE
|
target_link_libraries(UnleashedRecomp PRIVATE
|
||||||
comctl32
|
comctl32
|
||||||
|
dwmapi
|
||||||
ntdll
|
ntdll
|
||||||
winmm
|
Shcore
|
||||||
Synchronization
|
Synchronization
|
||||||
|
winmm
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -415,6 +418,8 @@ endfunction()
|
|||||||
|
|
||||||
compile_pixel_shader(blend_color_alpha_ps)
|
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_pixel_shader(csd_filter_ps)
|
||||||
compile_vertex_shader(csd_no_tex_vs)
|
compile_vertex_shader(csd_no_tex_vs)
|
||||||
compile_vertex_shader(csd_vs)
|
compile_vertex_shader(csd_vs)
|
||||||
@@ -428,6 +433,9 @@ compile_pixel_shader(imgui_ps)
|
|||||||
compile_vertex_shader(imgui_vs)
|
compile_vertex_shader(imgui_vs)
|
||||||
compile_pixel_shader(movie_ps)
|
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_2x)
|
||||||
compile_pixel_shader(resolve_msaa_depth_4x)
|
compile_pixel_shader(resolve_msaa_depth_4x)
|
||||||
compile_pixel_shader(resolve_msaa_depth_8x)
|
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/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/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/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.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/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/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/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/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")
|
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/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_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/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/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/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")
|
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")
|
||||||
|
|||||||
@@ -62,6 +62,10 @@
|
|||||||
#include "SWA/Camera/Camera.h"
|
#include "SWA/Camera/Camera.h"
|
||||||
#include "SWA/Camera/CameraController.h"
|
#include "SWA/Camera/CameraController.h"
|
||||||
#include "SWA/CharacterUtility/CharacterProxy.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/Globals.h"
|
||||||
#include "SWA/HUD/GeneralWindow/GeneralWindow.h"
|
#include "SWA/HUD/GeneralWindow/GeneralWindow.h"
|
||||||
#include "SWA/HUD/Loading/Loading.h"
|
#include "SWA/HUD/Loading/Loading.h"
|
||||||
@@ -80,6 +84,7 @@
|
|||||||
#include "SWA/Menu/MenuWindowBase.h"
|
#include "SWA/Menu/MenuWindowBase.h"
|
||||||
#include "SWA/Movie/MovieDisplayer.h"
|
#include "SWA/Movie/MovieDisplayer.h"
|
||||||
#include "SWA/Movie/MovieManager.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/EvilSonic.h"
|
||||||
#include "SWA/Player/Character/EvilSonic/EvilSonicContext.h"
|
#include "SWA/Player/Character/EvilSonic/EvilSonicContext.h"
|
||||||
#include "SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.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/TitleMenu.h"
|
||||||
#include "SWA/System/GameMode/Title/TitleStateBase.h"
|
#include "SWA/System/GameMode/Title/TitleStateBase.h"
|
||||||
#include "SWA/System/GameMode/Title/TitleStateIntro.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/Title/TitleStateWorldMap.h"
|
||||||
#include "SWA/System/GameMode/WorldMap/WorldMapCamera.h"
|
#include "SWA/System/GameMode/WorldMap/WorldMapCamera.h"
|
||||||
#include "SWA/System/GameMode/WorldMap/WorldMapCursor.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
|
namespace SWA
|
||||||
{
|
{
|
||||||
|
enum EWindowStatus : uint32_t
|
||||||
|
{
|
||||||
|
eWindowStatus_Closed,
|
||||||
|
eWindowStatus_OpeningMessage = 2,
|
||||||
|
eWindowStatus_DisplayingMessage,
|
||||||
|
eWindowStatus_OpeningControls,
|
||||||
|
eWindowStatus_DisplayingControls
|
||||||
|
};
|
||||||
|
|
||||||
class CGeneralWindow
|
class CGeneralWindow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -14,5 +23,20 @@ namespace SWA
|
|||||||
Chao::CSD::RCPtr<Chao::CSD::CScene> m_rcWindow_2;
|
Chao::CSD::RCPtr<Chao::CSD::CScene> m_rcWindow_2;
|
||||||
Chao::CSD::RCPtr<Chao::CSD::CScene> m_rcWindowSelect;
|
Chao::CSD::RCPtr<Chao::CSD::CScene> m_rcWindowSelect;
|
||||||
Chao::CSD::RCPtr<Chao::CSD::CScene> m_rcFooter;
|
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);
|
SWA_INSERT_PADDING(0x88);
|
||||||
Hedgehog::Base::CSharedString m_StageName;
|
Hedgehog::Base::CSharedString m_StageName;
|
||||||
xpointer<CSoundAdministrator> m_pSoundAdministrator;
|
xpointer<CSoundAdministrator> m_pSoundAdministrator;
|
||||||
SWA_INSERT_PADDING(0x124);
|
SWA_INSERT_PADDING(0x48);
|
||||||
|
xpointer<CGeneralWindow> m_pGeneralWindow;
|
||||||
|
SWA_INSERT_PADDING(0xD8);
|
||||||
SScoreInfo m_ScoreInfo;
|
SScoreInfo m_ScoreInfo;
|
||||||
SWA_INSERT_PADDING(0x0C);
|
SWA_INSERT_PADDING(0x0C);
|
||||||
};
|
};
|
||||||
@@ -60,6 +62,7 @@ namespace SWA
|
|||||||
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_spDatabase, 0x1C);
|
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_spDatabase, 0x1C);
|
||||||
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_StageName, 0xAC);
|
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_StageName, 0xAC);
|
||||||
SWA_ASSERT_OFFSETOF(CGameDocument::CMember, m_pSoundAdministrator, 0xB0);
|
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_OFFSETOF(CGameDocument::CMember, m_ScoreInfo, 0x1D8);
|
||||||
SWA_ASSERT_SIZEOF(CGameDocument::CMember, 0x230);
|
SWA_ASSERT_SIZEOF(CGameDocument::CMember, 0x230);
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,36 @@
|
|||||||
|
|
||||||
namespace SWA
|
namespace SWA
|
||||||
{
|
{
|
||||||
class CTitleMenu
|
class CTitleMenu : public CMenuWindowBase
|
||||||
{
|
{
|
||||||
public:
|
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;
|
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 {};
|
||||||
|
}
|
||||||
@@ -165,11 +165,7 @@ int GetThreadPriorityImpl(GuestThreadHandle* hThread)
|
|||||||
|
|
||||||
uint32_t SetThreadIdealProcessorImpl(GuestThreadHandle* hThread, uint32_t dwIdealProcessor)
|
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;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GUEST_FUNCTION_HOOK(sub_82DFA2E8, SetThreadNameImpl);
|
GUEST_FUNCTION_HOOK(sub_82DFA2E8, SetThreadNameImpl);
|
||||||
|
|||||||
@@ -221,6 +221,8 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
|
|||||||
for (size_t i = 0; i < atlas->ConfigData.size(); i++)
|
for (size_t i = 0; i < atlas->ConfigData.size(); i++)
|
||||||
{
|
{
|
||||||
auto& config = atlas->ConfigData[i];
|
auto& config = atlas->ConfigData[i];
|
||||||
|
bool increaseSpacing = strstr(config.Name, "Seurat") != nullptr;
|
||||||
|
|
||||||
auto& [index, count] = ranges[i];
|
auto& [index, count] = ranges[i];
|
||||||
for (size_t j = 0; j < count; j++)
|
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;
|
double x0, y0, x1, y1, u0, v0, u1, v1;
|
||||||
glyph.getQuadPlaneBounds(x0, y0, x1, y1);
|
glyph.getQuadPlaneBounds(x0, y0, x1, y1);
|
||||||
glyph.getQuadAtlasBounds(u0, v0, u1, v1);
|
glyph.getQuadAtlasBounds(u0, v0, u1, v1);
|
||||||
|
|
||||||
|
double advance = glyph.getAdvance();
|
||||||
|
if (increaseSpacing && glyph.getCodepoint() == ' ')
|
||||||
|
advance *= 1.5;
|
||||||
|
|
||||||
config.DstFont->AddGlyph(
|
config.DstFont->AddGlyph(
|
||||||
&config,
|
&config,
|
||||||
glyph.getCodepoint(),
|
glyph.getCodepoint(),
|
||||||
@@ -239,7 +246,7 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
|
|||||||
v1 / packer.height,
|
v1 / packer.height,
|
||||||
u1 / packer.width,
|
u1 / packer.width,
|
||||||
v0 / packer.height,
|
v0 / packer.height,
|
||||||
glyph.getAdvance());
|
advance);
|
||||||
}
|
}
|
||||||
|
|
||||||
config.DstFont->BuildLookupTable();
|
config.DstFont->BuildLookupTable();
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
//# define D3D12_DEBUG_LAYER_GPU_BASED_VALIDATION_ENABLED
|
//# define D3D12_DEBUG_LAYER_GPU_BASED_VALIDATION_ENABLED
|
||||||
#endif
|
#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.
|
// 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
|
#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)
|
#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) {
|
static void setObjectName(ID3D12Object *object, const std::string &name) {
|
||||||
const std::wstring wideCharName = Utf8ToUtf16(name);
|
const std::wstring wideCharName = Utf8ToUtf16(name);
|
||||||
object->SetName(wideCharName.c_str());
|
object->SetName(wideCharName.c_str());
|
||||||
@@ -1916,7 +1932,7 @@ namespace plume {
|
|||||||
resetSamplePositions();
|
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(dstTexture != nullptr);
|
||||||
assert(srcTexture != nullptr);
|
assert(srcTexture != nullptr);
|
||||||
|
|
||||||
@@ -1931,7 +1947,7 @@ namespace plume {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSamplePositions(interfaceDstTexture);
|
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();
|
resetSamplePositions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3373,6 +3389,10 @@ namespace plume {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef D3D12_DEBUG_SET_STABLE_POWER_STATE
|
||||||
|
d3d->SetStablePowerState(TRUE);
|
||||||
|
#endif
|
||||||
|
|
||||||
D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
|
D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
|
||||||
allocatorDesc.pDevice = d3d;
|
allocatorDesc.pDevice = d3d;
|
||||||
allocatorDesc.pAdapter = adapter;
|
allocatorDesc.pAdapter = adapter;
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ namespace plume {
|
|||||||
void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override;
|
void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override;
|
||||||
void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override;
|
void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override;
|
||||||
void resolveTexture(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 buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) override;
|
||||||
void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override;
|
void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override;
|
||||||
void discardTexture(const RenderTexture* texture) 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 copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) = 0;
|
||||||
virtual void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) = 0;
|
virtual void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) = 0;
|
||||||
virtual void resolveTexture(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 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 buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) = 0;
|
||||||
virtual void discardTexture(const RenderTexture* texture) = 0; // D3D12 only.
|
virtual void discardTexture(const RenderTexture* texture) = 0; // D3D12 only.
|
||||||
|
|||||||
@@ -483,6 +483,12 @@ namespace plume {
|
|||||||
CPU
|
CPU
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class RenderResolveMode {
|
||||||
|
MIN,
|
||||||
|
MAX,
|
||||||
|
AVERAGE
|
||||||
|
};
|
||||||
|
|
||||||
// Global functions.
|
// Global functions.
|
||||||
|
|
||||||
constexpr uint32_t RenderFormatSize(RenderFormat format) {
|
constexpr uint32_t RenderFormatSize(RenderFormat format) {
|
||||||
|
|||||||
@@ -3074,12 +3074,13 @@ namespace plume {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VulkanCommandList::resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) {
|
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(dstTexture != nullptr);
|
||||||
assert(srcTexture != nullptr);
|
assert(srcTexture != nullptr);
|
||||||
|
assert(resolveMode == RenderResolveMode::AVERAGE && "Vulkan only supports AVERAGE resolve mode.");
|
||||||
|
|
||||||
thread_local std::vector<VkImageResolve> imageResolves;
|
thread_local std::vector<VkImageResolve> imageResolves;
|
||||||
imageResolves.clear();
|
imageResolves.clear();
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ namespace plume {
|
|||||||
void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override;
|
void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override;
|
||||||
void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override;
|
void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override;
|
||||||
void resolveTexture(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 buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) override;
|
||||||
void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override;
|
void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override;
|
||||||
void discardTexture(const RenderTexture* texture) 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));
|
||||||
|
}
|
||||||
@@ -138,14 +138,14 @@ float4 main(in Interpolators interpolators) : SV_Target
|
|||||||
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_HORIZONTAL_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 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 *= minAlpha;
|
||||||
color.a *= maxAlpha;
|
color.a *= maxAlpha;
|
||||||
}
|
}
|
||||||
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE)
|
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE)
|
||||||
{
|
{
|
||||||
float minAlpha = saturate((interpolators.Position.y - g_PushConstants.BoundsMin.y) / g_PushConstants.Scale.y);
|
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);
|
float maxAlpha = saturate((g_PushConstants.BoundsMax.y - interpolators.Position.y) / g_PushConstants.Scale.y);
|
||||||
|
|
||||||
color.a *= minAlpha;
|
color.a *= minAlpha;
|
||||||
|
|||||||
@@ -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
|
#pragma once
|
||||||
|
|
||||||
struct PushConstants
|
#include "copy_common.hlsli"
|
||||||
{
|
|
||||||
uint ResourceDescriptorIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
[[vk::push_constant]] ConstantBuffer<PushConstants> g_PushConstants : register(b3, space4);
|
|
||||||
|
|
||||||
Texture2DMS<float, SAMPLE_COUNT> g_Texture2DMSDescriptorHeap[] : register(t0, space0);
|
Texture2DMS<float, SAMPLE_COUNT> g_Texture2DMSDescriptorHeap[] : register(t0, space0);
|
||||||
|
|
||||||
|
|||||||
+286
-103
@@ -26,6 +26,7 @@
|
|||||||
#include <ui/message_window.h>
|
#include <ui/message_window.h>
|
||||||
#include <ui/options_menu.h>
|
#include <ui/options_menu.h>
|
||||||
#include <ui/game_window.h>
|
#include <ui/game_window.h>
|
||||||
|
#include <ui/black_bar.h>
|
||||||
#include <patches/aspect_ratio_patches.h>
|
#include <patches/aspect_ratio_patches.h>
|
||||||
#include <user/config.h>
|
#include <user/config.h>
|
||||||
#include <sdl_listener.h>
|
#include <sdl_listener.h>
|
||||||
@@ -40,6 +41,8 @@
|
|||||||
#ifdef UNLEASHED_RECOMP_D3D12
|
#ifdef UNLEASHED_RECOMP_D3D12
|
||||||
#include "shader/blend_color_alpha_ps.hlsl.dxil.h"
|
#include "shader/blend_color_alpha_ps.hlsl.dxil.h"
|
||||||
#include "shader/copy_vs.hlsl.dxil.h"
|
#include "shader/copy_vs.hlsl.dxil.h"
|
||||||
|
#include "shader/copy_color_ps.hlsl.dxil.h"
|
||||||
|
#include "shader/copy_depth_ps.hlsl.dxil.h"
|
||||||
#include "shader/csd_filter_ps.hlsl.dxil.h"
|
#include "shader/csd_filter_ps.hlsl.dxil.h"
|
||||||
#include "shader/csd_no_tex_vs.hlsl.dxil.h"
|
#include "shader/csd_no_tex_vs.hlsl.dxil.h"
|
||||||
#include "shader/csd_vs.hlsl.dxil.h"
|
#include "shader/csd_vs.hlsl.dxil.h"
|
||||||
@@ -53,6 +56,9 @@
|
|||||||
#include "shader/imgui_vs.hlsl.dxil.h"
|
#include "shader/imgui_vs.hlsl.dxil.h"
|
||||||
#include "shader/movie_ps.hlsl.dxil.h"
|
#include "shader/movie_ps.hlsl.dxil.h"
|
||||||
#include "shader/movie_vs.hlsl.dxil.h"
|
#include "shader/movie_vs.hlsl.dxil.h"
|
||||||
|
#include "shader/resolve_msaa_color_2x.hlsl.dxil.h"
|
||||||
|
#include "shader/resolve_msaa_color_4x.hlsl.dxil.h"
|
||||||
|
#include "shader/resolve_msaa_color_8x.hlsl.dxil.h"
|
||||||
#include "shader/resolve_msaa_depth_2x.hlsl.dxil.h"
|
#include "shader/resolve_msaa_depth_2x.hlsl.dxil.h"
|
||||||
#include "shader/resolve_msaa_depth_4x.hlsl.dxil.h"
|
#include "shader/resolve_msaa_depth_4x.hlsl.dxil.h"
|
||||||
#include "shader/resolve_msaa_depth_8x.hlsl.dxil.h"
|
#include "shader/resolve_msaa_depth_8x.hlsl.dxil.h"
|
||||||
@@ -60,6 +66,8 @@
|
|||||||
|
|
||||||
#include "shader/blend_color_alpha_ps.hlsl.spirv.h"
|
#include "shader/blend_color_alpha_ps.hlsl.spirv.h"
|
||||||
#include "shader/copy_vs.hlsl.spirv.h"
|
#include "shader/copy_vs.hlsl.spirv.h"
|
||||||
|
#include "shader/copy_color_ps.hlsl.spirv.h"
|
||||||
|
#include "shader/copy_depth_ps.hlsl.spirv.h"
|
||||||
#include "shader/csd_filter_ps.hlsl.spirv.h"
|
#include "shader/csd_filter_ps.hlsl.spirv.h"
|
||||||
#include "shader/csd_no_tex_vs.hlsl.spirv.h"
|
#include "shader/csd_no_tex_vs.hlsl.spirv.h"
|
||||||
#include "shader/csd_vs.hlsl.spirv.h"
|
#include "shader/csd_vs.hlsl.spirv.h"
|
||||||
@@ -73,6 +81,9 @@
|
|||||||
#include "shader/imgui_vs.hlsl.spirv.h"
|
#include "shader/imgui_vs.hlsl.spirv.h"
|
||||||
#include "shader/movie_ps.hlsl.spirv.h"
|
#include "shader/movie_ps.hlsl.spirv.h"
|
||||||
#include "shader/movie_vs.hlsl.spirv.h"
|
#include "shader/movie_vs.hlsl.spirv.h"
|
||||||
|
#include "shader/resolve_msaa_color_2x.hlsl.spirv.h"
|
||||||
|
#include "shader/resolve_msaa_color_4x.hlsl.spirv.h"
|
||||||
|
#include "shader/resolve_msaa_color_8x.hlsl.spirv.h"
|
||||||
#include "shader/resolve_msaa_depth_2x.hlsl.spirv.h"
|
#include "shader/resolve_msaa_depth_2x.hlsl.spirv.h"
|
||||||
#include "shader/resolve_msaa_depth_4x.hlsl.spirv.h"
|
#include "shader/resolve_msaa_depth_4x.hlsl.spirv.h"
|
||||||
#include "shader/resolve_msaa_depth_8x.hlsl.spirv.h"
|
#include "shader/resolve_msaa_depth_8x.hlsl.spirv.h"
|
||||||
@@ -136,6 +147,14 @@ struct PipelineState
|
|||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
struct UploadAllocation
|
||||||
|
{
|
||||||
|
const RenderBuffer* buffer;
|
||||||
|
uint64_t offset;
|
||||||
|
uint8_t* memory;
|
||||||
|
uint64_t deviceAddress;
|
||||||
|
};
|
||||||
|
|
||||||
struct SharedConstants
|
struct SharedConstants
|
||||||
{
|
{
|
||||||
uint32_t texture2DIndices[16]{};
|
uint32_t texture2DIndices[16]{};
|
||||||
@@ -158,6 +177,8 @@ static RenderViewport g_viewport(0.0f, 0.0f, 1280.0f, 720.0f);
|
|||||||
static PipelineState g_pipelineState;
|
static PipelineState g_pipelineState;
|
||||||
static int32_t g_depthBias;
|
static int32_t g_depthBias;
|
||||||
static float g_slopeScaledDepthBias;
|
static float g_slopeScaledDepthBias;
|
||||||
|
static uint32_t g_vertexShaderConstants[0x400];
|
||||||
|
static uint32_t g_pixelShaderConstants[0x380];
|
||||||
static SharedConstants g_sharedConstants;
|
static SharedConstants g_sharedConstants;
|
||||||
static GuestTexture* g_textures[16];
|
static GuestTexture* g_textures[16];
|
||||||
static RenderSamplerDesc g_samplerDescs[16];
|
static RenderSamplerDesc g_samplerDescs[16];
|
||||||
@@ -215,6 +236,9 @@ static bool g_vulkan = false;
|
|||||||
static constexpr bool g_vulkan = true;
|
static constexpr bool g_vulkan = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static constexpr bool g_hardwareResolve = true;
|
||||||
|
static constexpr bool g_hardwareDepthResolve = true;
|
||||||
|
|
||||||
static std::unique_ptr<RenderInterface> g_interface;
|
static std::unique_ptr<RenderInterface> g_interface;
|
||||||
static std::unique_ptr<RenderDevice> g_device;
|
static std::unique_ptr<RenderDevice> g_device;
|
||||||
|
|
||||||
@@ -380,25 +404,14 @@ struct UploadBuffer
|
|||||||
uint64_t deviceAddress = 0;
|
uint64_t deviceAddress = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UploadAllocation
|
|
||||||
{
|
|
||||||
const RenderBuffer* buffer;
|
|
||||||
uint64_t offset;
|
|
||||||
uint8_t* memory;
|
|
||||||
uint64_t deviceAddress;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UploadAllocator
|
struct UploadAllocator
|
||||||
{
|
{
|
||||||
std::vector<UploadBuffer> buffers;
|
std::vector<UploadBuffer> buffers;
|
||||||
uint32_t index = 0;
|
uint32_t index = 0;
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
Mutex mutex;
|
|
||||||
|
|
||||||
UploadAllocation allocate(uint32_t size, uint32_t alignment)
|
UploadAllocation allocate(uint32_t size, uint32_t alignment)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(mutex);
|
|
||||||
|
|
||||||
assert(size <= UploadBuffer::SIZE);
|
assert(size <= UploadBuffer::SIZE);
|
||||||
|
|
||||||
offset = (offset + alignment - 1) & ~(alignment - 1);
|
offset = (offset + alignment - 1) & ~(alignment - 1);
|
||||||
@@ -459,6 +472,53 @@ struct UploadAllocator
|
|||||||
|
|
||||||
static UploadAllocator g_uploadAllocators[NUM_FRAMES];
|
static UploadAllocator g_uploadAllocators[NUM_FRAMES];
|
||||||
|
|
||||||
|
struct IntermediaryUploadAllocator
|
||||||
|
{
|
||||||
|
static constexpr size_t SIZE = 16 * 1024 * 1024;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<uint8_t[]>> buffers;
|
||||||
|
uint32_t index = 0;
|
||||||
|
uint32_t offset = 0;
|
||||||
|
|
||||||
|
uint8_t* allocate(uint32_t size)
|
||||||
|
{
|
||||||
|
assert(size <= SIZE);
|
||||||
|
|
||||||
|
if (offset + size > SIZE)
|
||||||
|
{
|
||||||
|
++index;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffers.size() <= index)
|
||||||
|
buffers.resize(index + 1);
|
||||||
|
|
||||||
|
auto& buffer = buffers[index];
|
||||||
|
if (buffer == nullptr)
|
||||||
|
buffer = std::make_unique_for_overwrite<uint8_t[]>(SIZE);
|
||||||
|
|
||||||
|
auto result = buffer.get() + offset;
|
||||||
|
offset += ((size + 0xF) & ~0xF);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* allocate(const void* memory, uint32_t size)
|
||||||
|
{
|
||||||
|
auto result = allocate(size);
|
||||||
|
memcpy(result, memory, size);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
index = 0;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static IntermediaryUploadAllocator g_intermediaryUploadAllocator;
|
||||||
|
|
||||||
static std::vector<GuestResource*> g_tempResources[NUM_FRAMES];
|
static std::vector<GuestResource*> g_tempResources[NUM_FRAMES];
|
||||||
static std::vector<std::unique_ptr<RenderBuffer>> g_tempBuffers[NUM_FRAMES];
|
static std::vector<std::unique_ptr<RenderBuffer>> g_tempBuffers[NUM_FRAMES];
|
||||||
|
|
||||||
@@ -563,7 +623,6 @@ static void DestructTempResources()
|
|||||||
if (texture->mappedMemory != nullptr)
|
if (texture->mappedMemory != nullptr)
|
||||||
g_userHeap.Free(texture->mappedMemory);
|
g_userHeap.Free(texture->mappedMemory);
|
||||||
|
|
||||||
if (texture->descriptorIndex != NULL)
|
|
||||||
g_textureDescriptorAllocator.free(texture->descriptorIndex);
|
g_textureDescriptorAllocator.free(texture->descriptorIndex);
|
||||||
|
|
||||||
if (texture->patchedTexture != nullptr)
|
if (texture->patchedTexture != nullptr)
|
||||||
@@ -807,12 +866,16 @@ struct RenderCommand
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
UploadAllocation allocation;
|
uint8_t* memory;
|
||||||
|
uint32_t index;
|
||||||
|
uint32_t size;
|
||||||
} setVertexShaderConstants;
|
} setVertexShaderConstants;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
UploadAllocation allocation;
|
uint8_t* memory;
|
||||||
|
uint32_t index;
|
||||||
|
uint32_t size;
|
||||||
} setPixelShaderConstants;
|
} setPixelShaderConstants;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
@@ -840,7 +903,8 @@ struct RenderCommand
|
|||||||
{
|
{
|
||||||
uint32_t primitiveType;
|
uint32_t primitiveType;
|
||||||
uint32_t primitiveCount;
|
uint32_t primitiveCount;
|
||||||
UploadAllocation vertexStreamZeroData;
|
uint8_t* vertexStreamZeroData;
|
||||||
|
uint32_t vertexStreamZeroSize;
|
||||||
uint32_t vertexStreamZeroStride;
|
uint32_t vertexStreamZeroStride;
|
||||||
CsdFilterState csdFilterState;
|
CsdFilterState csdFilterState;
|
||||||
} drawPrimitiveUP;
|
} drawPrimitiveUP;
|
||||||
@@ -1140,6 +1204,14 @@ static const std::pair<GuestRenderState, PPCFunc*> g_setRenderStateFunctions[] =
|
|||||||
{ D3DRS_COLORWRITEENABLE, HostToGuestFunction<SetRenderState<D3DRS_COLORWRITEENABLE>> }
|
{ D3DRS_COLORWRITEENABLE, HostToGuestFunction<SetRenderState<D3DRS_COLORWRITEENABLE>> }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static std::unique_ptr<RenderShader> g_copyShader;
|
||||||
|
|
||||||
|
static std::unique_ptr<RenderShader> g_copyColorShader;
|
||||||
|
static ankerl::unordered_dense::map<RenderFormat, std::unique_ptr<RenderPipeline>> g_copyColorPipelines;
|
||||||
|
static std::unique_ptr<RenderPipeline> g_copyDepthPipeline;
|
||||||
|
|
||||||
|
static std::unique_ptr<RenderShader> g_resolveMsaaColorShaders[3];
|
||||||
|
static ankerl::unordered_dense::map<RenderFormat, std::array<std::unique_ptr<RenderPipeline>, 3>> g_resolveMsaaColorPipelines;
|
||||||
static std::unique_ptr<RenderPipeline> g_resolveMsaaDepthPipelines[3];
|
static std::unique_ptr<RenderPipeline> g_resolveMsaaDepthPipelines[3];
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@@ -1712,7 +1784,23 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
|
|||||||
|
|
||||||
g_pipelineLayout = pipelineLayoutBuilder.create(g_device.get());
|
g_pipelineLayout = pipelineLayoutBuilder.create(g_device.get());
|
||||||
|
|
||||||
auto copyShader = CREATE_SHADER(copy_vs);
|
g_copyShader = CREATE_SHADER(copy_vs);
|
||||||
|
g_copyColorShader = CREATE_SHADER(copy_color_ps);
|
||||||
|
auto copyDepthShader = CREATE_SHADER(copy_depth_ps);
|
||||||
|
|
||||||
|
RenderGraphicsPipelineDesc desc;
|
||||||
|
desc.pipelineLayout = g_pipelineLayout.get();
|
||||||
|
desc.vertexShader = g_copyShader.get();
|
||||||
|
desc.pixelShader = copyDepthShader.get();
|
||||||
|
desc.depthFunction = RenderComparisonFunction::ALWAYS;
|
||||||
|
desc.depthEnabled = true;
|
||||||
|
desc.depthWriteEnabled = true;
|
||||||
|
desc.depthTargetFormat = RenderFormat::D32_FLOAT;
|
||||||
|
g_copyDepthPipeline = g_device->createGraphicsPipeline(desc);
|
||||||
|
|
||||||
|
g_resolveMsaaColorShaders[0] = CREATE_SHADER(resolve_msaa_color_2x);
|
||||||
|
g_resolveMsaaColorShaders[1] = CREATE_SHADER(resolve_msaa_color_4x);
|
||||||
|
g_resolveMsaaColorShaders[2] = CREATE_SHADER(resolve_msaa_color_8x);
|
||||||
|
|
||||||
for (size_t i = 0; i < std::size(g_resolveMsaaDepthPipelines); i++)
|
for (size_t i = 0; i < std::size(g_resolveMsaaDepthPipelines); i++)
|
||||||
{
|
{
|
||||||
@@ -1730,9 +1818,9 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderGraphicsPipelineDesc desc;
|
desc = {};
|
||||||
desc.pipelineLayout = g_pipelineLayout.get();
|
desc.pipelineLayout = g_pipelineLayout.get();
|
||||||
desc.vertexShader = copyShader.get();
|
desc.vertexShader = g_copyShader.get();
|
||||||
desc.pixelShader = pixelShader.get();
|
desc.pixelShader = pixelShader.get();
|
||||||
desc.depthFunction = RenderComparisonFunction::ALWAYS;
|
desc.depthFunction = RenderComparisonFunction::ALWAYS;
|
||||||
desc.depthEnabled = true;
|
desc.depthEnabled = true;
|
||||||
@@ -1759,9 +1847,9 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
|
|||||||
|
|
||||||
auto gammaCorrectionShader = CREATE_SHADER(gamma_correction_ps);
|
auto gammaCorrectionShader = CREATE_SHADER(gamma_correction_ps);
|
||||||
|
|
||||||
RenderGraphicsPipelineDesc desc;
|
desc = {};
|
||||||
desc.pipelineLayout = g_pipelineLayout.get();
|
desc.pipelineLayout = g_pipelineLayout.get();
|
||||||
desc.vertexShader = copyShader.get();
|
desc.vertexShader = g_copyShader.get();
|
||||||
desc.pixelShader = gammaCorrectionShader.get();
|
desc.pixelShader = gammaCorrectionShader.get();
|
||||||
desc.renderTargetFormat[0] = BACKBUFFER_FORMAT;
|
desc.renderTargetFormat[0] = BACKBUFFER_FORMAT;
|
||||||
desc.renderTargetBlend[0] = RenderBlendDesc::Copy();
|
desc.renderTargetBlend[0] = RenderBlendDesc::Copy();
|
||||||
@@ -2231,6 +2319,7 @@ static void DrawImGui()
|
|||||||
MessageWindow::Draw();
|
MessageWindow::Draw();
|
||||||
ButtonGuide::Draw();
|
ButtonGuide::Draw();
|
||||||
Fader::Draw();
|
Fader::Draw();
|
||||||
|
BlackBar::Draw();
|
||||||
|
|
||||||
assert(ImGui::GetForegroundDrawList()->_ClipRectStack.Size == 1 && "Some clip rects were not removed from the stack!");
|
assert(ImGui::GetForegroundDrawList()->_ClipRectStack.Size == 1 && "Some clip rects were not removed from the stack!");
|
||||||
|
|
||||||
@@ -2457,6 +2546,7 @@ void Video::Present()
|
|||||||
|
|
||||||
g_dirtyStates = DirtyStates(true);
|
g_dirtyStates = DirtyStates(true);
|
||||||
g_uploadAllocators[g_frame].reset();
|
g_uploadAllocators[g_frame].reset();
|
||||||
|
g_intermediaryUploadAllocator.reset();
|
||||||
g_triangleFanIndexData.reset();
|
g_triangleFanIndexData.reset();
|
||||||
g_quadIndexData.reset();
|
g_quadIndexData.reset();
|
||||||
|
|
||||||
@@ -2703,65 +2793,62 @@ static RenderFormat ConvertFormat(uint32_t format)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuestTexture::CreateTexture()
|
static GuestTexture* CreateTexture(uint32_t width, uint32_t height, uint32_t depth, uint32_t levels, uint32_t usage, uint32_t format, uint32_t pool, uint32_t type)
|
||||||
{
|
{
|
||||||
|
const auto texture = g_userHeap.AllocPhysical<GuestTexture>(type == 17 ? ResourceType::VolumeTexture : ResourceType::Texture);
|
||||||
|
|
||||||
RenderTextureDesc desc;
|
RenderTextureDesc desc;
|
||||||
desc.dimension = type == ResourceType::VolumeTexture ? RenderTextureDimension::TEXTURE_3D : RenderTextureDimension::TEXTURE_2D;
|
desc.dimension = texture->type == ResourceType::VolumeTexture ? RenderTextureDimension::TEXTURE_3D : RenderTextureDimension::TEXTURE_2D;
|
||||||
desc.width = width;
|
desc.width = width;
|
||||||
desc.height = height;
|
desc.height = height;
|
||||||
desc.depth = depth;
|
desc.depth = depth;
|
||||||
desc.mipLevels = levels;
|
desc.mipLevels = levels;
|
||||||
desc.arraySize = 1;
|
desc.arraySize = 1;
|
||||||
desc.format = format;
|
desc.format = ConvertFormat(format);
|
||||||
desc.flags = (desc.format == RenderFormat::D32_FLOAT) ? RenderTextureFlag::DEPTH_TARGET : RenderTextureFlag::NONE;
|
|
||||||
|
|
||||||
textureHolder = g_device->createTexture(desc);
|
if (desc.format == RenderFormat::D32_FLOAT)
|
||||||
texture = textureHolder.get();
|
desc.flags = RenderTextureFlag::DEPTH_TARGET;
|
||||||
|
else if (usage != 0)
|
||||||
|
desc.flags = RenderTextureFlag::RENDER_TARGET;
|
||||||
|
else
|
||||||
|
desc.flags = RenderTextureFlag::NONE;
|
||||||
|
|
||||||
|
texture->textureHolder = g_device->createTexture(desc);
|
||||||
|
texture->texture = texture->textureHolder.get();
|
||||||
|
|
||||||
RenderTextureViewDesc viewDesc;
|
RenderTextureViewDesc viewDesc;
|
||||||
viewDesc.format = desc.format;
|
viewDesc.format = desc.format;
|
||||||
viewDesc.dimension = type == ResourceType::VolumeTexture ? RenderTextureViewDimension::TEXTURE_3D : RenderTextureViewDimension::TEXTURE_2D;
|
viewDesc.dimension = texture->type == ResourceType::VolumeTexture ? RenderTextureViewDimension::TEXTURE_3D : RenderTextureViewDimension::TEXTURE_2D;
|
||||||
viewDesc.mipLevels = levels;
|
viewDesc.mipLevels = levels;
|
||||||
|
|
||||||
textureView = texture->createTextureView(viewDesc);
|
|
||||||
viewDimension = viewDesc.dimension;
|
|
||||||
|
|
||||||
descriptorIndex = g_textureDescriptorAllocator.allocate();
|
|
||||||
|
|
||||||
g_textureDescriptorSet->setTexture(descriptorIndex, texture, RenderTextureLayout::SHADER_READ, textureView.get());
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
texture->setName(fmt::format("Texture {:X}", g_memory.MapVirtual(this)));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static GuestTexture* CreateTexture(uint32_t width, uint32_t height, uint32_t depth, uint32_t levels, uint32_t usage, uint32_t format, uint32_t pool, uint32_t type)
|
|
||||||
{
|
|
||||||
const auto texture = g_userHeap.AllocPhysical<GuestTexture>(type == 17 ? ResourceType::VolumeTexture : ResourceType::Texture);
|
|
||||||
|
|
||||||
texture->width = width;
|
|
||||||
texture->height = height;
|
|
||||||
texture->depth = depth;
|
|
||||||
texture->levels = levels;
|
|
||||||
texture->format = ConvertFormat(format);
|
|
||||||
|
|
||||||
switch (format)
|
switch (format)
|
||||||
{
|
{
|
||||||
case D3DFMT_D24FS8:
|
case D3DFMT_D24FS8:
|
||||||
case D3DFMT_D24S8:
|
case D3DFMT_D24S8:
|
||||||
case D3DFMT_L8:
|
case D3DFMT_L8:
|
||||||
case D3DFMT_L8_2:
|
case D3DFMT_L8_2:
|
||||||
texture->componentMapping = RenderComponentMapping(RenderSwizzle::R, RenderSwizzle::R, RenderSwizzle::R, RenderSwizzle::ONE);
|
viewDesc.componentMapping = RenderComponentMapping(RenderSwizzle::R, RenderSwizzle::R, RenderSwizzle::R, RenderSwizzle::ONE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D3DFMT_X8R8G8B8:
|
case D3DFMT_X8R8G8B8:
|
||||||
texture->componentMapping = RenderComponentMapping(RenderSwizzle::G, RenderSwizzle::B, RenderSwizzle::A, RenderSwizzle::ONE);
|
viewDesc.componentMapping = RenderComponentMapping(RenderSwizzle::G, RenderSwizzle::B, RenderSwizzle::A, RenderSwizzle::ONE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render targets/depth stencil textures are lazily created to have VRAM savings when the copy bypass optimization manages to work.
|
texture->textureView = texture->texture->createTextureView(viewDesc);
|
||||||
if (usage == 0)
|
|
||||||
texture->CreateTexture();
|
texture->width = width;
|
||||||
|
texture->height = height;
|
||||||
|
texture->depth = depth;
|
||||||
|
texture->format = desc.format;
|
||||||
|
texture->viewDimension = viewDesc.dimension;
|
||||||
|
texture->descriptorIndex = g_textureDescriptorAllocator.allocate();
|
||||||
|
|
||||||
|
g_textureDescriptorSet->setTexture(texture->descriptorIndex, texture->texture, RenderTextureLayout::SHADER_READ, texture->textureView.get());
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
texture->texture->setName(fmt::format("Texture {:X}", g_memory.MapVirtual(texture)));
|
||||||
|
#endif
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
@@ -2984,36 +3071,31 @@ static bool PopulateBarriersForStretchRect(GuestSurface* renderTarget, GuestSurf
|
|||||||
|
|
||||||
RenderTextureLayout srcLayout;
|
RenderTextureLayout srcLayout;
|
||||||
RenderTextureLayout dstLayout;
|
RenderTextureLayout dstLayout;
|
||||||
|
bool shaderResolve = true;
|
||||||
|
|
||||||
if (multiSampling)
|
if (multiSampling && g_hardwareResolve)
|
||||||
{
|
{
|
||||||
if (surface == depthStencil)
|
// Hardware depth resolve is only supported on D3D12 when programmable sample positions are available.
|
||||||
{
|
bool hardwareDepthResolveAvailable = g_hardwareDepthResolve && !g_vulkan && g_capabilities.sampleLocations;
|
||||||
srcLayout = RenderTextureLayout::SHADER_READ;
|
|
||||||
dstLayout = RenderTextureLayout::DEPTH_WRITE;
|
if (surface->format != RenderFormat::D32_FLOAT || hardwareDepthResolveAvailable)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
srcLayout = RenderTextureLayout::RESOLVE_SOURCE;
|
srcLayout = RenderTextureLayout::RESOLVE_SOURCE;
|
||||||
dstLayout = RenderTextureLayout::RESOLVE_DEST;
|
dstLayout = RenderTextureLayout::RESOLVE_DEST;
|
||||||
|
shaderResolve = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (shaderResolve)
|
||||||
{
|
{
|
||||||
srcLayout = RenderTextureLayout::COPY_SOURCE;
|
srcLayout = RenderTextureLayout::SHADER_READ;
|
||||||
dstLayout = RenderTextureLayout::COPY_DEST;
|
dstLayout = (surface->format == RenderFormat::D32_FLOAT ? RenderTextureLayout::DEPTH_WRITE : RenderTextureLayout::COLOR_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddBarrier(surface, srcLayout);
|
AddBarrier(surface, srcLayout);
|
||||||
|
|
||||||
for (const auto texture : surface->destinationTextures)
|
for (const auto texture : surface->destinationTextures)
|
||||||
{
|
|
||||||
// Need to create here...
|
|
||||||
if (texture->textureHolder == nullptr)
|
|
||||||
texture->CreateTexture();
|
|
||||||
|
|
||||||
AddBarrier(texture, dstLayout);
|
AddBarrier(texture, dstLayout);
|
||||||
}
|
|
||||||
|
|
||||||
addedAny = true;
|
addedAny = true;
|
||||||
}
|
}
|
||||||
@@ -3034,12 +3116,28 @@ static void ExecutePendingStretchRectCommands(GuestSurface* renderTarget, GuestS
|
|||||||
|
|
||||||
for (const auto texture : surface->destinationTextures)
|
for (const auto texture : surface->destinationTextures)
|
||||||
{
|
{
|
||||||
// The texture doesn't need to be created at this point,
|
bool shaderResolve = true;
|
||||||
// since the barrier call would have already done it.
|
|
||||||
|
if (multiSampling && g_hardwareResolve)
|
||||||
|
{
|
||||||
|
bool hardwareDepthResolveAvailable = g_hardwareDepthResolve && !g_vulkan && g_capabilities.sampleLocations;
|
||||||
|
|
||||||
|
if (surface->format != RenderFormat::D32_FLOAT || hardwareDepthResolveAvailable)
|
||||||
|
{
|
||||||
|
if (surface->format == RenderFormat::D32_FLOAT)
|
||||||
|
commandList->resolveTextureRegion(texture->texture, 0, 0, surface->texture, nullptr, RenderResolveMode::MIN);
|
||||||
|
else
|
||||||
|
commandList->resolveTexture(texture->texture, surface->texture);
|
||||||
|
|
||||||
|
shaderResolve = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shaderResolve)
|
||||||
|
{
|
||||||
|
RenderPipeline* pipeline = nullptr;
|
||||||
|
|
||||||
if (multiSampling)
|
if (multiSampling)
|
||||||
{
|
|
||||||
if (surface == depthStencil)
|
|
||||||
{
|
{
|
||||||
uint32_t pipelineIndex = 0;
|
uint32_t pipelineIndex = 0;
|
||||||
|
|
||||||
@@ -3059,12 +3157,69 @@ static void ExecutePendingStretchRectCommands(GuestSurface* renderTarget, GuestS
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (texture->format == RenderFormat::D32_FLOAT)
|
||||||
|
{
|
||||||
|
pipeline = g_resolveMsaaDepthPipelines[pipelineIndex].get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto& resolveMsaaColorPipeline = g_resolveMsaaColorPipelines[surface->format][pipelineIndex];
|
||||||
|
if (resolveMsaaColorPipeline == nullptr)
|
||||||
|
{
|
||||||
|
RenderGraphicsPipelineDesc desc;
|
||||||
|
desc.pipelineLayout = g_pipelineLayout.get();
|
||||||
|
desc.vertexShader = g_copyShader.get();
|
||||||
|
desc.pixelShader = g_resolveMsaaColorShaders[pipelineIndex].get();
|
||||||
|
desc.renderTargetFormat[0] = texture->format;
|
||||||
|
desc.renderTargetBlend[0] = RenderBlendDesc::Copy();
|
||||||
|
desc.renderTargetCount = 1;
|
||||||
|
resolveMsaaColorPipeline = g_device->createGraphicsPipeline(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline = resolveMsaaColorPipeline.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (texture->format == RenderFormat::D32_FLOAT)
|
||||||
|
{
|
||||||
|
pipeline = g_copyDepthPipeline.get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto& copyColorPipeline = g_copyColorPipelines[surface->format];
|
||||||
|
if (copyColorPipeline == nullptr)
|
||||||
|
{
|
||||||
|
RenderGraphicsPipelineDesc desc;
|
||||||
|
desc.pipelineLayout = g_pipelineLayout.get();
|
||||||
|
desc.vertexShader = g_copyShader.get();
|
||||||
|
desc.pixelShader = g_copyColorShader.get();
|
||||||
|
desc.renderTargetFormat[0] = texture->format;
|
||||||
|
desc.renderTargetBlend[0] = RenderBlendDesc::Copy();
|
||||||
|
desc.renderTargetCount = 1;
|
||||||
|
copyColorPipeline = g_device->createGraphicsPipeline(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline = copyColorPipeline.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (texture->framebuffer == nullptr)
|
if (texture->framebuffer == nullptr)
|
||||||
|
{
|
||||||
|
if (texture->format == RenderFormat::D32_FLOAT)
|
||||||
{
|
{
|
||||||
RenderFramebufferDesc desc;
|
RenderFramebufferDesc desc;
|
||||||
desc.depthAttachment = texture->texture;
|
desc.depthAttachment = texture->texture;
|
||||||
texture->framebuffer = g_device->createFramebuffer(desc);
|
texture->framebuffer = g_device->createFramebuffer(desc);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RenderFramebufferDesc desc;
|
||||||
|
desc.colorAttachments = const_cast<const RenderTexture**>(&texture->texture);
|
||||||
|
desc.colorAttachmentsCount = 1;
|
||||||
|
texture->framebuffer = g_device->createFramebuffer(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (g_framebuffer != texture->framebuffer.get())
|
if (g_framebuffer != texture->framebuffer.get())
|
||||||
{
|
{
|
||||||
@@ -3072,7 +3227,7 @@ static void ExecutePendingStretchRectCommands(GuestSurface* renderTarget, GuestS
|
|||||||
g_framebuffer = texture->framebuffer.get();
|
g_framebuffer = texture->framebuffer.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
commandList->setPipeline(g_resolveMsaaDepthPipelines[pipelineIndex].get());
|
commandList->setPipeline(pipeline);
|
||||||
commandList->setViewports(RenderViewport(0.0f, 0.0f, float(texture->width), float(texture->height), 0.0f, 1.0f));
|
commandList->setViewports(RenderViewport(0.0f, 0.0f, float(texture->width), float(texture->height), 0.0f, 1.0f));
|
||||||
commandList->setScissors(RenderRect(0, 0, texture->width, texture->height));
|
commandList->setScissors(RenderRect(0, 0, texture->width, texture->height));
|
||||||
commandList->setGraphicsPushConstants(0, &surface->descriptorIndex, 0, sizeof(uint32_t));
|
commandList->setGraphicsPushConstants(0, &surface->descriptorIndex, 0, sizeof(uint32_t));
|
||||||
@@ -3085,19 +3240,10 @@ static void ExecutePendingStretchRectCommands(GuestSurface* renderTarget, GuestS
|
|||||||
|
|
||||||
if (g_vulkan)
|
if (g_vulkan)
|
||||||
{
|
{
|
||||||
g_dirtyStates.depthBias = true; // Static depth bias in MSAA pipeline invalidates dynamic depth bias.
|
g_dirtyStates.vertexShaderConstants = true; // The push constant call invalidates vertex shader constants.
|
||||||
g_dirtyStates.vertexShaderConstants = true;
|
g_dirtyStates.depthBias = true; // Static depth bias in copy pipeline invalidates dynamic depth bias.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
commandList->resolveTexture(texture->texture, surface->texture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
commandList->copyTexture(texture->texture, surface->texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture->sourceSurface = nullptr;
|
texture->sourceSurface = nullptr;
|
||||||
|
|
||||||
@@ -3319,10 +3465,6 @@ static void SetTexture(GuestDevice* device, uint32_t index, GuestTexture* textur
|
|||||||
|
|
||||||
static void SetTextureInRenderThread(uint32_t index, GuestTexture* texture)
|
static void SetTextureInRenderThread(uint32_t index, GuestTexture* texture)
|
||||||
{
|
{
|
||||||
// Only may happen for render target/depth stencil textures.
|
|
||||||
if (texture != nullptr && texture->textureHolder == nullptr)
|
|
||||||
texture->CreateTexture();
|
|
||||||
|
|
||||||
AddBarrier(texture, RenderTextureLayout::SHADER_READ);
|
AddBarrier(texture, RenderTextureLayout::SHADER_READ);
|
||||||
|
|
||||||
auto viewDimension = texture != nullptr ? texture->viewDimension : RenderTextureViewDimension::UNKNOWN;
|
auto viewDimension = texture != nullptr ? texture->viewDimension : RenderTextureViewDimension::UNKNOWN;
|
||||||
@@ -3864,20 +4006,38 @@ static void FlushRenderStateForMainThread(GuestDevice* device, LocalRenderComman
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_dirtyStates.vertexShaderConstants || device->dirtyFlags[0] != 0)
|
uint64_t dirtyFlags = device->dirtyFlags[0].get();
|
||||||
|
if (dirtyFlags != 0)
|
||||||
{
|
{
|
||||||
|
int startRegister = std::countl_zero(dirtyFlags);
|
||||||
|
int endRegister = 64 - std::countr_zero(dirtyFlags);
|
||||||
|
|
||||||
|
uint32_t index = startRegister * 16;
|
||||||
|
uint32_t size = (endRegister - startRegister) * 64;
|
||||||
|
|
||||||
auto& cmd = queue.enqueue();
|
auto& cmd = queue.enqueue();
|
||||||
cmd.type = RenderCommandType::SetVertexShaderConstants;
|
cmd.type = RenderCommandType::SetVertexShaderConstants;
|
||||||
cmd.setVertexShaderConstants.allocation = g_uploadAllocators[g_frame].allocate<true>(device->vertexShaderFloatConstants, 0x1000, 0x100);
|
cmd.setVertexShaderConstants.memory = g_intermediaryUploadAllocator.allocate(&device->vertexShaderFloatConstants[index], size);
|
||||||
|
cmd.setVertexShaderConstants.index = index;
|
||||||
|
cmd.setVertexShaderConstants.size = size;
|
||||||
|
|
||||||
device->dirtyFlags[0] = 0;
|
device->dirtyFlags[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_dirtyStates.pixelShaderConstants || device->dirtyFlags[1] != 0)
|
dirtyFlags = device->dirtyFlags[1].get();
|
||||||
|
if (dirtyFlags != 0)
|
||||||
{
|
{
|
||||||
|
int startRegister = std::countl_zero(dirtyFlags);
|
||||||
|
int endRegister = std::min(56, 64 - std::countr_zero(dirtyFlags));
|
||||||
|
|
||||||
|
uint32_t index = startRegister * 16;
|
||||||
|
uint32_t size = (endRegister - startRegister) * 64;
|
||||||
|
|
||||||
auto& cmd = queue.enqueue();
|
auto& cmd = queue.enqueue();
|
||||||
cmd.type = RenderCommandType::SetPixelShaderConstants;
|
cmd.type = RenderCommandType::SetPixelShaderConstants;
|
||||||
cmd.setPixelShaderConstants.allocation = g_uploadAllocators[g_frame].allocate<true>(device->pixelShaderFloatConstants, 0xE00, 0x100);
|
cmd.setPixelShaderConstants.memory = g_intermediaryUploadAllocator.allocate(&device->pixelShaderFloatConstants[index], size);
|
||||||
|
cmd.setPixelShaderConstants.index = index;
|
||||||
|
cmd.setPixelShaderConstants.size = size;
|
||||||
|
|
||||||
device->dirtyFlags[1] = 0;
|
device->dirtyFlags[1] = 0;
|
||||||
}
|
}
|
||||||
@@ -3938,12 +4098,20 @@ static void ProcSetSamplerState(const RenderCommand& cmd)
|
|||||||
|
|
||||||
static void ProcSetVertexShaderConstants(const RenderCommand& cmd)
|
static void ProcSetVertexShaderConstants(const RenderCommand& cmd)
|
||||||
{
|
{
|
||||||
SetRootDescriptor(cmd.setVertexShaderConstants.allocation, 0);
|
auto& args = cmd.setVertexShaderConstants;
|
||||||
|
assert((args.index * sizeof(uint32_t) + args.size) <= sizeof(g_vertexShaderConstants));
|
||||||
|
|
||||||
|
memcpy(&g_vertexShaderConstants[args.index], args.memory, args.size);
|
||||||
|
g_dirtyStates.vertexShaderConstants = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ProcSetPixelShaderConstants(const RenderCommand& cmd)
|
static void ProcSetPixelShaderConstants(const RenderCommand& cmd)
|
||||||
{
|
{
|
||||||
SetRootDescriptor(cmd.setPixelShaderConstants.allocation, 1);
|
auto& args = cmd.setPixelShaderConstants;
|
||||||
|
assert((args.index * sizeof(uint32_t) + args.size) <= sizeof(g_pixelShaderConstants));
|
||||||
|
|
||||||
|
memcpy(&g_pixelShaderConstants[args.index], args.memory, args.size);
|
||||||
|
g_dirtyStates.pixelShaderConstants = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ProcAddPipeline(const RenderCommand& cmd)
|
static void ProcAddPipeline(const RenderCommand& cmd)
|
||||||
@@ -4033,6 +4201,18 @@ static void FlushRenderStateForRenderThread()
|
|||||||
if (g_dirtyStates.depthBias && g_capabilities.dynamicDepthBias)
|
if (g_dirtyStates.depthBias && g_capabilities.dynamicDepthBias)
|
||||||
commandList->setDepthBias(g_depthBias, 0.0f, g_slopeScaledDepthBias);
|
commandList->setDepthBias(g_depthBias, 0.0f, g_slopeScaledDepthBias);
|
||||||
|
|
||||||
|
if (g_dirtyStates.vertexShaderConstants)
|
||||||
|
{
|
||||||
|
auto vertexShaderConstants = g_uploadAllocators[g_frame].allocate<true>(g_vertexShaderConstants, sizeof(g_vertexShaderConstants), 0x100);
|
||||||
|
SetRootDescriptor(vertexShaderConstants, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_dirtyStates.pixelShaderConstants)
|
||||||
|
{
|
||||||
|
auto pixelShaderConstants = g_uploadAllocators[g_frame].allocate<true>(g_pixelShaderConstants, sizeof(g_pixelShaderConstants), 0x100);
|
||||||
|
SetRootDescriptor(pixelShaderConstants, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (g_dirtyStates.sharedConstants)
|
if (g_dirtyStates.sharedConstants)
|
||||||
{
|
{
|
||||||
auto sharedConstants = g_uploadAllocators[g_frame].allocate<false>(&g_sharedConstants, sizeof(g_sharedConstants), 0x100);
|
auto sharedConstants = g_uploadAllocators[g_frame].allocate<false>(&g_sharedConstants, sizeof(g_sharedConstants), 0x100);
|
||||||
@@ -4192,7 +4372,8 @@ static void DrawPrimitiveUP(GuestDevice* device, uint32_t primitiveType, uint32_
|
|||||||
cmd.type = RenderCommandType::DrawPrimitiveUP;
|
cmd.type = RenderCommandType::DrawPrimitiveUP;
|
||||||
cmd.drawPrimitiveUP.primitiveType = primitiveType;
|
cmd.drawPrimitiveUP.primitiveType = primitiveType;
|
||||||
cmd.drawPrimitiveUP.primitiveCount = primitiveCount;
|
cmd.drawPrimitiveUP.primitiveCount = primitiveCount;
|
||||||
cmd.drawPrimitiveUP.vertexStreamZeroData = g_uploadAllocators[g_frame].allocate<true>(reinterpret_cast<uint32_t*>(vertexStreamZeroData), primitiveCount * vertexStreamZeroStride, 0x4);
|
cmd.drawPrimitiveUP.vertexStreamZeroData = g_intermediaryUploadAllocator.allocate(vertexStreamZeroData, primitiveCount * vertexStreamZeroStride);
|
||||||
|
cmd.drawPrimitiveUP.vertexStreamZeroSize = primitiveCount * vertexStreamZeroStride;
|
||||||
cmd.drawPrimitiveUP.vertexStreamZeroStride = vertexStreamZeroStride;
|
cmd.drawPrimitiveUP.vertexStreamZeroStride = vertexStreamZeroStride;
|
||||||
cmd.drawPrimitiveUP.csdFilterState = g_csdFilterState;
|
cmd.drawPrimitiveUP.csdFilterState = g_csdFilterState;
|
||||||
|
|
||||||
@@ -4210,9 +4391,11 @@ static void ProcDrawPrimitiveUP(const RenderCommand& cmd)
|
|||||||
SetPrimitiveType(args.primitiveType);
|
SetPrimitiveType(args.primitiveType);
|
||||||
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.vertexStrides[0], uint8_t(args.vertexStreamZeroStride));
|
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.vertexStrides[0], uint8_t(args.vertexStreamZeroStride));
|
||||||
|
|
||||||
|
auto allocation = g_uploadAllocators[g_frame].allocate<true>(reinterpret_cast<const uint32_t*>(args.vertexStreamZeroData), args.vertexStreamZeroSize, 0x4);
|
||||||
|
|
||||||
auto& vertexBufferView = g_vertexBufferViews[0];
|
auto& vertexBufferView = g_vertexBufferViews[0];
|
||||||
vertexBufferView.size = args.primitiveCount * args.vertexStreamZeroStride;
|
vertexBufferView.size = args.primitiveCount * args.vertexStreamZeroStride;
|
||||||
vertexBufferView.buffer = args.vertexStreamZeroData.buffer->at(args.vertexStreamZeroData.offset);
|
vertexBufferView.buffer = allocation.buffer->at(allocation.offset);
|
||||||
g_inputSlots[0].stride = args.vertexStreamZeroStride;
|
g_inputSlots[0].stride = args.vertexStreamZeroStride;
|
||||||
g_dirtyStates.vertexStreamFirst = 0;
|
g_dirtyStates.vertexStreamFirst = 0;
|
||||||
|
|
||||||
@@ -4797,8 +4980,6 @@ static std::thread g_renderThread([]
|
|||||||
default: assert(false && "Unrecognized render command type."); break;
|
default: assert(false && "Unrecognized render command type."); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::this_thread::yield();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -6792,14 +6973,14 @@ PPC_FUNC(sub_82E328D8)
|
|||||||
class SDLEventListenerForPSOCaching : public SDLEventListener
|
class SDLEventListenerForPSOCaching : public SDLEventListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void OnSDLEvent(SDL_Event* event) override
|
bool OnSDLEvent(SDL_Event* event) override
|
||||||
{
|
{
|
||||||
if (event->type != SDL_QUIT)
|
if (event->type != SDL_QUIT)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
std::lock_guard lock(g_pipelineCacheMutex);
|
std::lock_guard lock(g_pipelineCacheMutex);
|
||||||
if (g_pipelineStatesToCache.empty())
|
if (g_pipelineStatesToCache.empty())
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
FILE* f = fopen("send_this_file_to_skyth.txt", "ab");
|
FILE* f = fopen("send_this_file_to_skyth.txt", "ab");
|
||||||
if (f != nullptr)
|
if (f != nullptr)
|
||||||
@@ -6914,6 +7095,8 @@ public:
|
|||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SDLEventListenerForPSOCaching g_sdlEventListenerForPSOCaching;
|
SDLEventListenerForPSOCaching g_sdlEventListenerForPSOCaching;
|
||||||
|
|||||||
@@ -154,15 +154,11 @@ struct GuestBaseTexture : GuestResource
|
|||||||
struct GuestTexture : GuestBaseTexture
|
struct GuestTexture : GuestBaseTexture
|
||||||
{
|
{
|
||||||
uint32_t depth = 0;
|
uint32_t depth = 0;
|
||||||
uint32_t levels = 0;
|
|
||||||
RenderTextureViewDimension viewDimension = RenderTextureViewDimension::UNKNOWN;
|
RenderTextureViewDimension viewDimension = RenderTextureViewDimension::UNKNOWN;
|
||||||
RenderComponentMapping componentMapping;
|
|
||||||
void* mappedMemory = nullptr;
|
void* mappedMemory = nullptr;
|
||||||
std::unique_ptr<RenderFramebuffer> framebuffer;
|
std::unique_ptr<RenderFramebuffer> framebuffer;
|
||||||
std::unique_ptr<GuestTexture> patchedTexture;
|
std::unique_ptr<GuestTexture> patchedTexture;
|
||||||
struct GuestSurface* sourceSurface = nullptr;
|
struct GuestSurface* sourceSurface = nullptr;
|
||||||
|
|
||||||
void CreateTexture();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GuestLockedRect
|
struct GuestLockedRect
|
||||||
|
|||||||
@@ -239,12 +239,16 @@ int HID_OnSDLEvent(void*, SDL_Event* event)
|
|||||||
if (event->type == SDL_CONTROLLERAXISMOTION)
|
if (event->type == SDL_CONTROLLERAXISMOTION)
|
||||||
{
|
{
|
||||||
if (abs(event->caxis.value) > 8000)
|
if (abs(event->caxis.value) > 8000)
|
||||||
|
{
|
||||||
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
SetControllerInputDevice(controller);
|
SetControllerInputDevice(controller);
|
||||||
|
}
|
||||||
|
|
||||||
controller->PollAxis();
|
controller->PollAxis();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
SetControllerInputDevice(controller);
|
SetControllerInputDevice(controller);
|
||||||
|
|
||||||
controller->Poll();
|
controller->Poll();
|
||||||
@@ -261,8 +265,14 @@ int HID_OnSDLEvent(void*, SDL_Event* event)
|
|||||||
case SDL_MOUSEMOTION:
|
case SDL_MOUSEMOTION:
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
case SDL_MOUSEBUTTONUP:
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
{
|
||||||
|
if (!GameWindow::IsFullscreen() || GameWindow::s_isFullscreenCursorVisible)
|
||||||
|
SDL_ShowCursor(SDL_ENABLE);
|
||||||
|
|
||||||
hid::g_inputDevice = hid::EInputDevice::Mouse;
|
hid::g_inputDevice = hid::EInputDevice::Mouse;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_WINDOWEVENT:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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 std::string filename(pair.first);
|
||||||
const uint32_t hashCount = pair.second;
|
const uint32_t hashCount = pair.second;
|
||||||
if (!sourceVfs.exists(filename))
|
if (!sourceVfs.exists(filename))
|
||||||
@@ -139,7 +139,13 @@ static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFi
|
|||||||
}
|
}
|
||||||
|
|
||||||
journal.progressCounter += fileData.size();
|
journal.progressCounter += fileData.size();
|
||||||
progressCallback();
|
|
||||||
|
if (!progressCallback())
|
||||||
|
{
|
||||||
|
journal.lastResult = Journal::Result::Cancelled;
|
||||||
|
journal.lastErrorMessage = "Installation was cancelled.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -266,7 +272,7 @@ bool Installer::computeTotalSize(std::span<const FilePair> filePairs, const uint
|
|||||||
return true;
|
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;
|
std::error_code ec;
|
||||||
if (!std::filesystem::exists(targetDirectory) && !std::filesystem::create_directories(targetDirectory, 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;
|
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
|
// 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.
|
// 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.
|
// Update the progress with the artificial amount attributed to the patching.
|
||||||
journal.progressCounter += PatcherContribution;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ struct Journal
|
|||||||
enum class Result
|
enum class Result
|
||||||
{
|
{
|
||||||
Success,
|
Success,
|
||||||
|
Cancelled,
|
||||||
VirtualFileSystemFailed,
|
VirtualFileSystemFailed,
|
||||||
DirectoryCreationFailed,
|
DirectoryCreationFailed,
|
||||||
FileMissing,
|
FileMissing,
|
||||||
@@ -75,10 +76,10 @@ struct Installer
|
|||||||
static bool checkDLCInstall(const std::filesystem::path &baseDirectory, DLC dlc);
|
static bool checkDLCInstall(const std::filesystem::path &baseDirectory, DLC dlc);
|
||||||
static bool checkAllDLC(const std::filesystem::path &baseDirectory);
|
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 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 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 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);
|
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.
|
// Convenience method for checking if the specified file contains the game. This should be used when the user selects the file.
|
||||||
|
|||||||
@@ -27,11 +27,11 @@
|
|||||||
CONFIG_DEFINE_LOCALE(Language)
|
CONFIG_DEFINE_LOCALE(Language)
|
||||||
{
|
{
|
||||||
{ ELanguage::English, { "Language", "Change the language used for text and logos." } },
|
{ ELanguage::English, { "Language", "Change the language used for text and logos." } },
|
||||||
{ ELanguage::Japanese, { "言語", "[PLACEHOLDER]" } },
|
{ ELanguage::Japanese, { "言語", "" } },
|
||||||
{ ELanguage::German, { "Sprache", "[PLACEHOLDER]" } },
|
{ ELanguage::German, { "Sprache", "" } },
|
||||||
{ ELanguage::French, { "Langue", "[PLACEHOLDER]" } },
|
{ ELanguage::French, { "Langue", "" } },
|
||||||
{ ELanguage::Spanish, { "Idioma", "[PLACEHOLDER]" } },
|
{ ELanguage::Spanish, { "Idioma", "" } },
|
||||||
{ ELanguage::Italian, { "Lingua", "[PLACEHOLDER]" } }
|
{ ELanguage::Italian, { "Lingua", "" } }
|
||||||
};
|
};
|
||||||
|
|
||||||
CONFIG_DEFINE_ENUM_LOCALE(ELanguage)
|
CONFIG_DEFINE_ENUM_LOCALE(ELanguage)
|
||||||
@@ -196,7 +196,7 @@ CONFIG_DEFINE_LOCALE(MusicAttenuation)
|
|||||||
|
|
||||||
CONFIG_DEFINE_LOCALE(ChannelConfiguration)
|
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)
|
CONFIG_DEFINE_ENUM_LOCALE(EChannelConfiguration)
|
||||||
@@ -246,7 +246,9 @@ CONFIG_DEFINE_ENUM_LOCALE(EAspectRatio)
|
|||||||
ELanguage::English,
|
ELanguage::English,
|
||||||
{
|
{
|
||||||
{ EAspectRatio::Auto, { "AUTO", "Auto: the aspect ratio will dynamically adjust to the window size." } },
|
{ 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)
|
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)
|
CONFIG_DEFINE_LOCALE(AntiAliasing)
|
||||||
@@ -306,9 +308,7 @@ CONFIG_DEFINE_ENUM_LOCALE(EShadowResolution)
|
|||||||
{
|
{
|
||||||
ELanguage::English,
|
ELanguage::English,
|
||||||
{
|
{
|
||||||
{ EShadowResolution::Original, { "ORIGINAL", "Original: the game will automatically determine the resolution of the shadows." } },
|
{ 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." } },
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -353,7 +353,7 @@ CONFIG_DEFINE_LOCALE(XboxColorCorrection)
|
|||||||
|
|
||||||
CONFIG_DEFINE_LOCALE(CutsceneAspectRatio)
|
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)
|
CONFIG_DEFINE_ENUM_LOCALE(ECutsceneAspectRatio)
|
||||||
@@ -361,24 +361,24 @@ CONFIG_DEFINE_ENUM_LOCALE(ECutsceneAspectRatio)
|
|||||||
{
|
{
|
||||||
ELanguage::English,
|
ELanguage::English,
|
||||||
{
|
{
|
||||||
{ ECutsceneAspectRatio::Original, { "ORIGINAL", "" } },
|
{ ECutsceneAspectRatio::Original, { "ORIGINAL", "Original: locks cutscenes to their original 16:9 aspect ratio." } },
|
||||||
{ ECutsceneAspectRatio::Unlocked, { "UNLOCKED", "" } },
|
{ 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,
|
ELanguage::English,
|
||||||
{
|
{
|
||||||
{ EUIScaleMode::Edge, { "EDGE", "Edge: the UI will anchor to the edges of the display." } },
|
{ EUIAlignmentMode::Edge, { "EDGE", "Edge: the UI will align with the edges of the display." } },
|
||||||
{ EUIScaleMode::Centre, { "CENTER", "Center: the UI will anchor to the center of the display." } },
|
{ EUIAlignmentMode::Centre, { "CENTER", "Center: the UI will align with the center of the display." } },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -189,8 +189,8 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
|
|||||||
{
|
{
|
||||||
"Installer_Page_CheckSpace",
|
"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::English, "The content will be installed to the program's folder.\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::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" }
|
{ ELanguage::Italian, "SALTA" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Installer_Button_Retry",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "RETRY" }
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Installer_Button_AddFiles",
|
"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.
|
// Notes: message appears when clicking the "Add Files" option for the first time.
|
||||||
"Installer_Message_FilePickerTutorial",
|
"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.
|
// Notes: message appears when clicking the "Add Folder" option for the first time.
|
||||||
"Installer_Message_FolderPickerTutorial",
|
"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?" }
|
{ 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.
|
// Notes: message appears when pressing B at the title screen.
|
||||||
"Title_Message_Quit",
|
"Title_Message_Quit",
|
||||||
@@ -446,6 +466,18 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
|
|||||||
{ ELanguage::Italian, "Indietro" }
|
{ ELanguage::Italian, "Indietro" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Common_Quit",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "Quit" },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Common_Cancel",
|
||||||
|
{
|
||||||
|
{ ELanguage::English, "Cancel" }
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Common_Reset",
|
"Common_Reset",
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -203,12 +203,12 @@ int main(int argc, char *argv[])
|
|||||||
if (!Video::CreateHostDevice(sdlVideoDriver))
|
if (!Video::CreateHostDevice(sdlVideoDriver))
|
||||||
{
|
{
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
|
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))
|
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))
|
if (!Video::CreateHostDevice(sdlVideoDriver))
|
||||||
{
|
{
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
|
||||||
return 1;
|
std::_Exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
#include <api/SWA.h>
|
#include <api/SWA.h>
|
||||||
|
#include <cpu/guest_stack_var.h>
|
||||||
#include <locale/locale.h>
|
#include <locale/locale.h>
|
||||||
|
#include <os/logger.h>
|
||||||
#include <ui/button_guide.h>
|
#include <ui/button_guide.h>
|
||||||
#include <ui/fader.h>
|
#include <ui/fader.h>
|
||||||
#include <ui/message_window.h>
|
#include <ui/message_window.h>
|
||||||
#include <ui/options_menu.h>
|
#include <ui/options_menu.h>
|
||||||
|
#include <user/achievement_manager.h>
|
||||||
#include <user/paths.h>
|
#include <user/paths.h>
|
||||||
#include <app.h>
|
#include <app.h>
|
||||||
#include <exports.h>
|
#include <exports.h>
|
||||||
@@ -50,12 +53,14 @@ PPC_FUNC_IMPL(__imp__sub_825882B8);
|
|||||||
PPC_FUNC(sub_825882B8)
|
PPC_FUNC(sub_825882B8)
|
||||||
{
|
{
|
||||||
auto pTitleState = (SWA::CTitleStateBase*)g_memory.Translate(ctx.r3.u32);
|
auto pTitleState = (SWA::CTitleStateBase*)g_memory.Translate(ctx.r3.u32);
|
||||||
|
auto pGameDocument = SWA::CGameDocument::GetInstance();
|
||||||
|
|
||||||
auto pInputState = SWA::CInputState::GetInstance();
|
auto pInputState = SWA::CInputState::GetInstance();
|
||||||
auto& pPadState = pInputState->GetPadState();
|
auto& pPadState = pInputState->GetPadState();
|
||||||
auto isAccepted = pPadState.IsTapped(SWA::eKeyState_A) || pPadState.IsTapped(SWA::eKeyState_Start);
|
auto isAccepted = pPadState.IsTapped(SWA::eKeyState_A) || pPadState.IsTapped(SWA::eKeyState_Start);
|
||||||
|
|
||||||
auto pContext = pTitleState->GetContextBase<SWA::CTitleStateBase::CTitleStateContext>();
|
auto pContext = pTitleState->GetContextBase<SWA::CTitleStateBase::CTitleStateContext>();
|
||||||
|
auto isNewGameIndex = pContext->m_pTitleMenu->m_CursorIndex == 0;
|
||||||
auto isOptionsIndex = pContext->m_pTitleMenu->m_CursorIndex == 2;
|
auto isOptionsIndex = pContext->m_pTitleMenu->m_CursorIndex == 2;
|
||||||
auto isInstallIndex = pContext->m_pTitleMenu->m_CursorIndex == 3;
|
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)
|
if (App::s_isSaveDataCorrupt && pContext->m_pTitleMenu->m_CursorIndex == 1)
|
||||||
pContext->m_pTitleMenu->m_CursorIndex = 0;
|
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)
|
if (OptionsMenu::s_isRestartRequired)
|
||||||
{
|
{
|
||||||
@@ -76,7 +91,6 @@ PPC_FUNC(sub_825882B8)
|
|||||||
{
|
{
|
||||||
Game_PlaySound("sys_worldmap_window");
|
Game_PlaySound("sys_worldmap_window");
|
||||||
Game_PlaySound("sys_worldmap_decide");
|
Game_PlaySound("sys_worldmap_decide");
|
||||||
|
|
||||||
OptionsMenu::Open();
|
OptionsMenu::Open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,7 +107,6 @@ PPC_FUNC(sub_825882B8)
|
|||||||
if (OptionsMenu::CanClose() && pPadState.IsTapped(SWA::eKeyState_B))
|
if (OptionsMenu::CanClose() && pPadState.IsTapped(SWA::eKeyState_B))
|
||||||
{
|
{
|
||||||
Game_PlaySound("sys_worldmap_cansel");
|
Game_PlaySound("sys_worldmap_cansel");
|
||||||
|
|
||||||
OptionsMenu::Close();
|
OptionsMenu::Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
#include <api/SWA.h>
|
#include <api/SWA.h>
|
||||||
#include <app.h>
|
#include <app.h>
|
||||||
#include <ui/game_window.h>
|
#include <ui/game_window.h>
|
||||||
|
#include <ui/black_bar.h>
|
||||||
#include <gpu/video.h>
|
#include <gpu/video.h>
|
||||||
|
#include <xxHashMap.h>
|
||||||
|
|
||||||
#include "aspect_ratio_patches.h"
|
#include "aspect_ratio_patches.h"
|
||||||
#include "camera_patches.h"
|
#include "camera_patches.h"
|
||||||
@@ -271,7 +273,7 @@ PPC_FUNC(sub_8258B558)
|
|||||||
ctx.f1.f64 = offsetX + g_aspectRatioNarrowScale * 140.0f;
|
ctx.f1.f64 = offsetX + g_aspectRatioNarrowScale * 140.0f;
|
||||||
ctx.f2.f64 = offsetY;
|
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;
|
ctx.f1.f64 += g_aspectRatioOffsetX / g_aspectRatioScale;
|
||||||
|
|
||||||
sub_830BB3D0(ctx, base);
|
sub_830BB3D0(ctx, base);
|
||||||
@@ -293,7 +295,7 @@ PPC_FUNC(sub_8258B558)
|
|||||||
if (textBox != NULL)
|
if (textBox != NULL)
|
||||||
{
|
{
|
||||||
float value = 708.0f + g_aspectRatioNarrowScale * 140.0f;
|
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;
|
value += g_aspectRatioOffsetX / g_aspectRatioScale;
|
||||||
|
|
||||||
PPC_STORE_U32(textBox + 0x38, reinterpret_cast<uint32_t&>(value));
|
PPC_STORE_U32(textBox + 0x38, reinterpret_cast<uint32_t&>(value));
|
||||||
@@ -339,6 +341,9 @@ enum
|
|||||||
REPEAT_LEFT = 1 << 15,
|
REPEAT_LEFT = 1 << 15,
|
||||||
|
|
||||||
TORNADO_DEFENSE = 1 << 16,
|
TORNADO_DEFENSE = 1 << 16,
|
||||||
|
|
||||||
|
LOADING_BLACK_BAR_MIN = 1 << 17,
|
||||||
|
LOADING_BLACK_BAR_MAX = 1 << 18,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CsdModifier
|
struct CsdModifier
|
||||||
@@ -348,7 +353,7 @@ struct CsdModifier
|
|||||||
uint32_t cornerIndex{};
|
uint32_t cornerIndex{};
|
||||||
};
|
};
|
||||||
|
|
||||||
static const ankerl::unordered_dense::map<XXH64_hash_t, CsdModifier> g_modifiers =
|
static const xxHashMap<CsdModifier> g_modifiers =
|
||||||
{
|
{
|
||||||
// ui_balloon
|
// ui_balloon
|
||||||
{ HashStr("ui_balloon/window/bg"), { STRETCH } },
|
{ 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/letterbox_top"), { STRETCH } },
|
||||||
{ HashStr("ui_loading/n_2_d/letterbox/black_l"), { EXTEND_LEFT | STRETCH_VERTICAL } },
|
{ 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/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
|
// ui_mediaroom
|
||||||
{ HashStr("ui_mediaroom/header/bg/img_1"), { EXTEND_LEFT } },
|
{ 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
|
// ui_missionscreen
|
||||||
{ HashStr("ui_missionscreen/player_count"), { ALIGN_TOP_LEFT | SCALE } },
|
{ HashStr("ui_missionscreen/player_count"), { ALIGN_TOP_LEFT | SCALE } },
|
||||||
{ HashStr("ui_missionscreen/time_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/time_count/position_S/bg_1"), { ALIGN_TOP_LEFT | SCALE | EXTEND_LEFT } },
|
||||||
{ HashStr("ui_missionscreen/item_count"), { ALIGN_TOP_LEFT | SCALE } },
|
{ 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"), { 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"), { 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
|
// ui_misson
|
||||||
{ HashStr("ui_misson/bg"), { STRETCH } },
|
{ HashStr("ui_misson/bg"), { STRETCH } },
|
||||||
@@ -878,7 +917,7 @@ static void Draw(PPCContext& ctx, uint8_t* base, PPCFunc* original, uint32_t str
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config::UIScaleMode == EUIScaleMode::Centre)
|
if (Config::UIAlignmentMode == EUIAlignmentMode::Centre)
|
||||||
{
|
{
|
||||||
if (g_aspectRatio >= WIDE_ASPECT_RATIO)
|
if (g_aspectRatio >= WIDE_ASPECT_RATIO)
|
||||||
modifier.flags &= ~(ALIGN_LEFT | ALIGN_RIGHT);
|
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);
|
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)
|
if ((modifier.flags & REPEAT_LEFT) != 0)
|
||||||
{
|
{
|
||||||
float width = *getPosition(2) - *getPosition(0);
|
float width = *getPosition(2) - *getPosition(0);
|
||||||
@@ -1147,8 +1198,8 @@ PPC_FUNC(sub_830D1EF0)
|
|||||||
y = g_aspectRatioOffsetY + (y + 0.5f) * g_aspectRatioScale;
|
y = g_aspectRatioOffsetY + (y + 0.5f) * g_aspectRatioScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
vertex[i].x = ((x - 0.5f) / Video::s_viewportWidth) * 2.0f - 1.0f;
|
vertex[i].x = ((round(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].y = ((round(y) - 0.5f) / Video::s_viewportHeight) * -2.0f + 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool letterboxTop = PPC_LOAD_U8(r3.u32 + PRIMITIVE_2D_PADDING_OFFSET + 0x1);
|
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;
|
double scaleOffset = (1280.0 * (1.0 - g_aspectRatioGameplayScale)) * g_aspectRatioScale;
|
||||||
|
|
||||||
if (Config::UIScaleMode == EUIScaleMode::Edge)
|
if (Config::UIAlignmentMode == EUIAlignmentMode::Edge)
|
||||||
{
|
{
|
||||||
if (type != 47) // Medal
|
if (type != 47) // Medal
|
||||||
x += g_aspectRatioOffsetX * 2.0 + scaleOffset;
|
x += g_aspectRatioOffsetX * 2.0 + scaleOffset;
|
||||||
}
|
}
|
||||||
else if (Config::UIScaleMode == EUIScaleMode::Centre)
|
else if (Config::UIAlignmentMode == EUIAlignmentMode::Centre)
|
||||||
{
|
{
|
||||||
x += g_aspectRatioOffsetX + scaleOffset;
|
x += g_aspectRatioOffsetX + scaleOffset;
|
||||||
}
|
}
|
||||||
@@ -1362,6 +1413,12 @@ PPC_FUNC(sub_82B8AA40)
|
|||||||
|
|
||||||
// Restore the original letterbox value.
|
// Restore the original letterbox value.
|
||||||
PPC_STORE_U8(r3.u32, letterbox);
|
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)
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -115,10 +115,7 @@ PPC_FUNC(sub_8312DBF8)
|
|||||||
constexpr auto INTERVAL = 1000000000ns / 60;
|
constexpr auto INTERVAL = 1000000000ns / 60;
|
||||||
auto next = now + (INTERVAL - now.time_since_epoch() % INTERVAL);
|
auto next = now + (INTERVAL - now.time_since_epoch() % INTERVAL);
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::floor<std::chrono::milliseconds>(next - now - 1ms));
|
std::this_thread::sleep_until(next);
|
||||||
|
|
||||||
while (std::chrono::steady_clock::now() < next)
|
|
||||||
std::this_thread::yield();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitVsyncMidAsmHook()
|
void WaitVsyncMidAsmHook()
|
||||||
@@ -128,3 +125,37 @@ void WaitVsyncMidAsmHook()
|
|||||||
void ApplicationFrameLimiterMidAsmHook()
|
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;
|
bool m_isF8KeyDown = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void OnSDLEvent(SDL_Event* event) override
|
bool OnSDLEvent(SDL_Event* event) override
|
||||||
{
|
{
|
||||||
if (!Config::HUDToggleHotkey || OptionsMenu::s_isVisible)
|
if (!Config::HUDToggleHotkey || OptionsMenu::s_isVisible)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
switch (event->type)
|
switch (event->type)
|
||||||
{
|
{
|
||||||
@@ -34,6 +34,8 @@ public:
|
|||||||
m_isF8KeyDown = event->key.keysym.sym != SDLK_F8;
|
m_isF8KeyDown = event->key.keysym.sym != SDLK_F8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_frontendListener;
|
g_frontendListener;
|
||||||
|
|||||||
@@ -121,10 +121,10 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnSDLEvent(SDL_Event* event) override
|
bool OnSDLEvent(SDL_Event* event) override
|
||||||
{
|
{
|
||||||
if (!hid::IsInputAllowed())
|
if (!hid::IsInputAllowed())
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
switch (event->type)
|
switch (event->type)
|
||||||
{
|
{
|
||||||
@@ -202,6 +202,8 @@ public:
|
|||||||
ms_touchpadFingerCount--;
|
ms_touchpadFingerCount--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_sdlEventListenerForInputPatches;
|
g_sdlEventListenerForInputPatches;
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
inline const char* g_credits[] =
|
inline std::array<const char*, 14> g_credits =
|
||||||
{
|
{
|
||||||
"Skyth",
|
"Skyth",
|
||||||
"Hyper",
|
"Hyper",
|
||||||
"Darío",
|
"Darío",
|
||||||
"Sajid",
|
"Sajid",
|
||||||
|
"DeaThProj",
|
||||||
"RadiantDerg",
|
"RadiantDerg",
|
||||||
"PTKay",
|
"PTKay",
|
||||||
"DeaThProj",
|
|
||||||
"SuperSonic16",
|
"SuperSonic16",
|
||||||
"NextinHKRY",
|
"NextinHKRY",
|
||||||
"M&M",
|
|
||||||
"saguinee",
|
"saguinee",
|
||||||
"LadyLunanova",
|
"LadyLunanova",
|
||||||
"LJSTAR"
|
"LJSTAR",
|
||||||
|
"Goalringmod27",
|
||||||
|
"M&M"
|
||||||
};
|
};
|
||||||
|
|
||||||
inline size_t g_creditsSize = 12;
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
VERSION_MILESTONE="Beta 1"
|
VERSION_MILESTONE="Beta 2"
|
||||||
VERSION_MAJOR=1
|
VERSION_MAJOR=1
|
||||||
VERSION_MINOR=0
|
VERSION_MINOR=0
|
||||||
VERSION_REVISION=0
|
VERSION_REVISION=0
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class ISDLEventListener
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~ISDLEventListener() = default;
|
virtual ~ISDLEventListener() = default;
|
||||||
virtual void OnSDLEvent(SDL_Event* event) = 0;
|
virtual bool OnSDLEvent(SDL_Event* event) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::vector<ISDLEventListener*>& GetEventListeners();
|
extern std::vector<ISDLEventListener*>& GetEventListeners();
|
||||||
@@ -17,5 +17,5 @@ public:
|
|||||||
GetEventListeners().emplace_back(this);
|
GetEventListeners().emplace_back(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnSDLEvent(SDL_Event* event) override {}
|
bool OnSDLEvent(SDL_Event* event) override { return false; }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ void AchievementOverlay::Draw()
|
|||||||
|
|
||||||
void AchievementOverlay::Open(int id)
|
void AchievementOverlay::Open(int id)
|
||||||
{
|
{
|
||||||
if (s_isVisible)
|
if (s_isVisible && !g_isClosing)
|
||||||
{
|
{
|
||||||
s_queue.emplace(id);
|
s_queue.emplace(id);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
};
|
||||||
@@ -38,7 +38,8 @@ std::unordered_map<EButtonIcon, float> g_iconWidths =
|
|||||||
{ EButtonIcon::Start, 40 },
|
{ EButtonIcon::Start, 40 },
|
||||||
{ EButtonIcon::Back, 40 },
|
{ EButtonIcon::Back, 40 },
|
||||||
{ EButtonIcon::LMB, 40 },
|
{ EButtonIcon::LMB, 40 },
|
||||||
{ EButtonIcon::Enter, 40 }
|
{ EButtonIcon::Enter, 40 },
|
||||||
|
{ EButtonIcon::Escape, 40 },
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<EButtonIcon, float> g_iconHeights =
|
std::unordered_map<EButtonIcon, float> g_iconHeights =
|
||||||
@@ -56,7 +57,8 @@ std::unordered_map<EButtonIcon, float> g_iconHeights =
|
|||||||
{ EButtonIcon::Start, 40 },
|
{ EButtonIcon::Start, 40 },
|
||||||
{ EButtonIcon::Back, 40 },
|
{ EButtonIcon::Back, 40 },
|
||||||
{ EButtonIcon::LMB, 40 },
|
{ EButtonIcon::LMB, 40 },
|
||||||
{ EButtonIcon::Enter, 40 }
|
{ EButtonIcon::Enter, 40 },
|
||||||
|
{ EButtonIcon::Escape, 40 },
|
||||||
};
|
};
|
||||||
|
|
||||||
std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon icon)
|
std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon icon)
|
||||||
@@ -124,12 +126,17 @@ std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EButtonIcon::LMB:
|
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();
|
texture = g_upKBMIcons.get();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EButtonIcon::Enter:
|
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();
|
texture = g_upKBMIcons.get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ enum class EButtonIcon
|
|||||||
|
|
||||||
// Keyboard + Mouse (temporary)
|
// Keyboard + Mouse (temporary)
|
||||||
LMB,
|
LMB,
|
||||||
Enter
|
Enter,
|
||||||
|
Escape
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EButtonAlignment
|
enum class EButtonAlignment
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#include <dwmapi.h>
|
#include <dwmapi.h>
|
||||||
#pragma comment(lib, "dwmapi.lib")
|
#include <shellscalingapi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <res/images/game_icon.bmp.h>
|
#include <res/images/game_icon.bmp.h>
|
||||||
@@ -24,7 +24,12 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
|
|||||||
ImGui_ImplSDL2_ProcessEvent(event);
|
ImGui_ImplSDL2_ProcessEvent(event);
|
||||||
|
|
||||||
for (auto listener : GetEventListeners())
|
for (auto listener : GetEventListeners())
|
||||||
listener->OnSDLEvent(event);
|
{
|
||||||
|
if (listener->OnSDLEvent(event))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (event->type)
|
switch (event->type)
|
||||||
{
|
{
|
||||||
@@ -141,20 +146,6 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
|
|||||||
break;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +170,7 @@ void GameWindow::Init(const char* sdlVideoDriver)
|
|||||||
SDL_AddEventWatch(Window_OnSDLEvent, s_pWindow);
|
SDL_AddEventWatch(Window_OnSDLEvent, s_pWindow);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SetProcessDPIAware();
|
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Config::WindowSize.LockCallback = [](ConfigDef<int32_t>* def)
|
Config::WindowSize.LockCallback = [](ConfigDef<int32_t>* def)
|
||||||
@@ -437,7 +428,7 @@ void GameWindow::ResetDimensions()
|
|||||||
|
|
||||||
uint32_t GameWindow::GetWindowFlags()
|
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)
|
if (Config::WindowState == EWindowState::Maximised)
|
||||||
flags |= SDL_WINDOW_MAXIMIZED;
|
flags |= SDL_WINDOW_MAXIMIZED;
|
||||||
@@ -475,6 +466,9 @@ void GameWindow::SetDisplay(int displayIndex)
|
|||||||
if (!IsFullscreen())
|
if (!IsFullscreen())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (GetDisplay() == displayIndex)
|
||||||
|
return;
|
||||||
|
|
||||||
s_isChangingDisplay = true;
|
s_isChangingDisplay = true;
|
||||||
|
|
||||||
SDL_Rect bounds;
|
SDL_Rect bounds;
|
||||||
|
|||||||
@@ -6,20 +6,17 @@
|
|||||||
|
|
||||||
#include <res/images/common/general_window.dds.h>
|
#include <res/images/common/general_window.dds.h>
|
||||||
#include <res/images/common/light.dds.h>
|
#include <res/images/common/light.dds.h>
|
||||||
#include <res/images/common/select_fade.dds.h>
|
#include <res/images/common/select.dds.h>
|
||||||
#include <res/images/common/select_fill.dds.h>
|
|
||||||
|
|
||||||
std::unique_ptr<GuestTexture> g_texGeneralWindow;
|
std::unique_ptr<GuestTexture> g_texGeneralWindow;
|
||||||
std::unique_ptr<GuestTexture> g_texLight;
|
std::unique_ptr<GuestTexture> g_texLight;
|
||||||
std::unique_ptr<GuestTexture> g_texSelectFade;
|
std::unique_ptr<GuestTexture> g_texSelect;
|
||||||
std::unique_ptr<GuestTexture> g_texSelectFill;
|
|
||||||
|
|
||||||
void InitImGuiUtils()
|
void InitImGuiUtils()
|
||||||
{
|
{
|
||||||
g_texGeneralWindow = LOAD_ZSTD_TEXTURE(g_general_window);
|
g_texGeneralWindow = LOAD_ZSTD_TEXTURE(g_general_window);
|
||||||
g_texLight = LOAD_ZSTD_TEXTURE(g_light);
|
g_texLight = LOAD_ZSTD_TEXTURE(g_light);
|
||||||
g_texSelectFade = LOAD_ZSTD_TEXTURE(g_select_fade);
|
g_texSelect = LOAD_ZSTD_TEXTURE(g_select);
|
||||||
g_texSelectFill = LOAD_ZSTD_TEXTURE(g_select_fill);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetGradient(const ImVec2& min, const ImVec2& max, ImU32 top, ImU32 bottom)
|
void SetGradient(const ImVec2& min, const ImVec2& max, ImU32 top, ImU32 bottom)
|
||||||
@@ -80,7 +77,7 @@ void ResetTextSkew()
|
|||||||
SetScale({ 1.0f, 1.0f });
|
SetScale({ 1.0f, 1.0f });
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
|
void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScaleLeft, float fadeScaleRight)
|
||||||
{
|
{
|
||||||
auto callbackData = AddImGuiCallback(ImGuiCallback::SetMarqueeFade);
|
auto callbackData = AddImGuiCallback(ImGuiCallback::SetMarqueeFade);
|
||||||
callbackData->setMarqueeFade.boundsMin[0] = min.x;
|
callbackData->setMarqueeFade.boundsMin[0] = min.x;
|
||||||
@@ -89,10 +86,15 @@ void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
|
|||||||
callbackData->setMarqueeFade.boundsMax[1] = max.y;
|
callbackData->setMarqueeFade.boundsMax[1] = max.y;
|
||||||
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE);
|
SetShaderModifier(IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE);
|
||||||
SetScale({ fadeScale, 1.0f });
|
SetScale({ fadeScaleLeft, fadeScaleRight });
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
|
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);
|
auto callbackData = AddImGuiCallback(ImGuiCallback::SetMarqueeFade);
|
||||||
callbackData->setMarqueeFade.boundsMin[0] = min.x;
|
callbackData->setMarqueeFade.boundsMin[0] = min.x;
|
||||||
@@ -101,7 +103,12 @@ void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
|
|||||||
callbackData->setMarqueeFade.boundsMax[1] = max.y;
|
callbackData->setMarqueeFade.boundsMax[1] = max.y;
|
||||||
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE);
|
SetShaderModifier(IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE);
|
||||||
SetScale({ 1.0f, fadeScale });
|
SetScale({ fadeScaleTop, fadeScaleBottom });
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale)
|
||||||
|
{
|
||||||
|
SetVerticalMarqueeFade(min, max, fadeScale, fadeScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetMarqueeFade()
|
void ResetMarqueeFade()
|
||||||
@@ -353,7 +360,8 @@ std::string Truncate(const std::string& input, size_t maxLength, bool useEllipsi
|
|||||||
return input;
|
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::string output;
|
||||||
std::map<std::string, std::string> rubyMap;
|
std::map<std::string, std::string> rubyMap;
|
||||||
std::string currentMain, currentRuby;
|
std::string currentMain, currentRuby;
|
||||||
@@ -400,7 +408,8 @@ std::pair<std::string, std::map<std::string, std::string>> RemoveRubyAnnotations
|
|||||||
return { output, rubyMap };
|
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;
|
std::string annotatedText;
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
size_t length = wrappedText.length();
|
size_t length = wrappedText.length();
|
||||||
@@ -445,6 +454,7 @@ std::vector<std::string> Split(const char* strStart, const ImFont *font, float f
|
|||||||
const char *lineStart = strStart;
|
const char *lineStart = strStart;
|
||||||
const bool wordWrapEnabled = (maxWidth > 0.0f);
|
const bool wordWrapEnabled = (maxWidth > 0.0f);
|
||||||
const char *wordWrapEOL = nullptr;
|
const char *wordWrapEOL = nullptr;
|
||||||
|
|
||||||
while (*str != 0)
|
while (*str != 0)
|
||||||
{
|
{
|
||||||
if (wordWrapEnabled)
|
if (wordWrapEnabled)
|
||||||
@@ -572,10 +582,9 @@ std::vector<std::string> RemoveAnnotationFromParagraph(const std::vector<std::st
|
|||||||
for (auto& annotatedLine : paragraph.lines)
|
for (auto& annotatedLine : paragraph.lines)
|
||||||
{
|
{
|
||||||
std::string annotationRemovedLine = "";
|
std::string annotationRemovedLine = "";
|
||||||
|
|
||||||
for (const auto& segment : annotatedLine)
|
for (const auto& segment : annotatedLine)
|
||||||
{
|
|
||||||
annotationRemovedLine += segment.text;
|
annotationRemovedLine += segment.text;
|
||||||
}
|
|
||||||
|
|
||||||
result.push_back(annotationRemovedLine);
|
result.push_back(annotationRemovedLine);
|
||||||
}
|
}
|
||||||
@@ -588,9 +597,7 @@ std::string RemoveAnnotationFromParagraphLine(const std::vector<TextSegment>& an
|
|||||||
std::string result = "";
|
std::string result = "";
|
||||||
|
|
||||||
for (auto& segment : annotatedLine)
|
for (auto& segment : annotatedLine)
|
||||||
{
|
|
||||||
result += segment.text;
|
result += segment.text;
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -603,25 +610,19 @@ ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMar
|
|||||||
const auto paragraph = CalculateAnnotatedParagraph(lines);
|
const auto paragraph = CalculateAnnotatedParagraph(lines);
|
||||||
|
|
||||||
std::vector<std::string> annotationRemovedLines;
|
std::vector<std::string> annotationRemovedLines;
|
||||||
|
|
||||||
for (const auto& line : paragraph.lines)
|
for (const auto& line : paragraph.lines)
|
||||||
{
|
|
||||||
annotationRemovedLines.emplace_back(RemoveAnnotationFromParagraphLine(line));
|
annotationRemovedLines.emplace_back(RemoveAnnotationFromParagraphLine(line));
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < annotationRemovedLines.size(); i++)
|
for (size_t i = 0; i < annotationRemovedLines.size(); i++)
|
||||||
{
|
{
|
||||||
auto& line = annotationRemovedLines[i];
|
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, annotationRemovedLines[i].c_str());
|
||||||
|
|
||||||
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, line.c_str());
|
|
||||||
auto annotationSize = font->CalcTextSizeA(fontSize * ANNOTATION_FONT_SIZE_MODIFIER, FLT_MAX, 0, "");
|
|
||||||
|
|
||||||
x = std::max(x, textSize.x);
|
x = std::max(x, textSize.x);
|
||||||
y += textSize.y + Scale(lineMargin);
|
y += textSize.y + Scale(lineMargin);
|
||||||
|
|
||||||
if (paragraph.annotated)
|
if (paragraph.annotated && i != (annotationRemovedLines.size() - 1))
|
||||||
{
|
y += fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
|
||||||
y += annotationSize.y;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { x, y };
|
return { x, y };
|
||||||
@@ -629,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)
|
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)
|
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);
|
const auto input = RemoveRubyAnnotations(text);
|
||||||
auto lines = Split(input.first.c_str(), font, fontSize, maxWidth);
|
auto lines = Split(input.first.c_str(), font, fontSize, maxWidth);
|
||||||
|
|
||||||
for (auto& line : lines)
|
for (auto& line : lines)
|
||||||
{
|
|
||||||
line = ReAddRubyAnnotations(line, input.second);
|
line = ReAddRubyAnnotations(line, input.second);
|
||||||
}
|
|
||||||
|
|
||||||
auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines);
|
auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines);
|
||||||
float offsetY = 0.0f;
|
auto offsetY = 0.0f;
|
||||||
|
|
||||||
const auto paragraph = CalculateAnnotatedParagraph(lines);
|
const auto paragraph = CalculateAnnotatedParagraph(lines);
|
||||||
|
|
||||||
@@ -655,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 textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, annotationRemovedLine.c_str());
|
||||||
auto annotationSize = font->CalcTextSizeA(annotationFontSize, FLT_MAX, 0, "");
|
auto annotationSize = font->CalcTextSizeA(annotationFontSize, FLT_MAX, 0, "");
|
||||||
|
auto textX = pos.x;
|
||||||
float textX = pos.x;
|
auto textY = pos.y + offsetY;
|
||||||
float textY = pos.y + offsetY;
|
|
||||||
|
|
||||||
if (isCentred)
|
if (isCentred)
|
||||||
{
|
{
|
||||||
@@ -681,16 +685,16 @@ void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
drawMethod(segment.text.c_str(), { textX, textY });
|
drawMethod(segment.text.c_str(), { textX, textY });
|
||||||
|
|
||||||
textX += textSize.x;
|
textX += textSize.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
offsetY += textSize.y + Scale(lineMargin);
|
offsetY += textSize.y + Scale(lineMargin);
|
||||||
|
|
||||||
if (paragraph.annotated)
|
if (paragraph.annotated)
|
||||||
{
|
|
||||||
offsetY += annotationSize.y;
|
offsetY += annotationSize.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
float Lerp(float a, float b, float t)
|
float Lerp(float a, float b, float t)
|
||||||
{
|
{
|
||||||
@@ -753,32 +757,32 @@ void DrawSelectionContainer(ImVec2 min, ImVec2 max, bool fadeTop)
|
|||||||
auto centre = PIXELS_TO_UV_COORDS(64, 64, 11, 0, 8, 50);
|
auto centre = PIXELS_TO_UV_COORDS(64, 64, 11, 0, 8, 50);
|
||||||
auto right = PIXELS_TO_UV_COORDS(64, 64, 19, 0, 11, 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_texSelect.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_texSelect.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(), { max.x - commonWidth, min.y }, max, GET_UV_COORDS(right), colour);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tl = PIXELS_TO_UV_COORDS(64, 64, 0, 0, 11, 24);
|
auto tl = PIXELS_TO_UV_COORDS(64, 64, 34, 0, 11, 24);
|
||||||
auto tc = PIXELS_TO_UV_COORDS(64, 64, 11, 0, 8, 24);
|
auto tc = PIXELS_TO_UV_COORDS(64, 64, 45, 0, 8, 24);
|
||||||
auto tr = PIXELS_TO_UV_COORDS(64, 64, 19, 0, 11, 24);
|
auto tr = PIXELS_TO_UV_COORDS(64, 64, 53, 0, 11, 24);
|
||||||
auto cl = PIXELS_TO_UV_COORDS(64, 64, 0, 24, 11, 2);
|
auto cl = PIXELS_TO_UV_COORDS(64, 64, 34, 24, 11, 2);
|
||||||
auto cc = PIXELS_TO_UV_COORDS(64, 64, 11, 24, 8, 2);
|
auto cc = PIXELS_TO_UV_COORDS(64, 64, 45, 24, 8, 2);
|
||||||
auto cr = PIXELS_TO_UV_COORDS(64, 64, 19, 24, 11, 2);
|
auto cr = PIXELS_TO_UV_COORDS(64, 64, 53, 24, 11, 2);
|
||||||
auto bl = PIXELS_TO_UV_COORDS(64, 64, 0, 26, 11, 24);
|
auto bl = PIXELS_TO_UV_COORDS(64, 64, 34, 26, 11, 24);
|
||||||
auto bc = PIXELS_TO_UV_COORDS(64, 64, 11, 26, 8, 24);
|
auto bc = PIXELS_TO_UV_COORDS(64, 64, 45, 26, 8, 24);
|
||||||
auto br = PIXELS_TO_UV_COORDS(64, 64, 19, 26, 11, 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_texSelect.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_texSelect.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_texSelect.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_texSelect.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_texSelect.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_texSelect.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_texSelect.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_texSelect.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(), { max.x - commonWidth, max.y - commonHeight }, { max.x, max.y }, GET_UV_COORDS(br), colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha)
|
void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha)
|
||||||
|
|||||||
@@ -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_texGeneralWindow;
|
||||||
extern std::unique_ptr<GuestTexture> g_texLight;
|
extern std::unique_ptr<GuestTexture> g_texLight;
|
||||||
extern std::unique_ptr<GuestTexture> g_texSelectFade;
|
extern std::unique_ptr<GuestTexture> g_texSelect;
|
||||||
extern std::unique_ptr<GuestTexture> g_texSelectFill;
|
|
||||||
|
|
||||||
struct TextSegment {
|
struct TextSegment {
|
||||||
bool annotated;
|
bool annotated;
|
||||||
@@ -42,7 +41,9 @@ void SetOrigin(ImVec2 origin);
|
|||||||
void SetScale(ImVec2 scale);
|
void SetScale(ImVec2 scale);
|
||||||
void SetTextSkew(float yCenter, float skewScale);
|
void SetTextSkew(float yCenter, float skewScale);
|
||||||
void ResetTextSkew();
|
void ResetTextSkew();
|
||||||
|
void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScaleLeft, float fadeScaleRight);
|
||||||
void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale);
|
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 SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale);
|
||||||
void ResetMarqueeFade();
|
void ResetMarqueeFade();
|
||||||
void SetOutline(float outline);
|
void SetOutline(float outline);
|
||||||
|
|||||||
@@ -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 CONTAINER_INNER_DURATION = 15.0;
|
||||||
|
|
||||||
static constexpr double ALL_ANIMATIONS_FULL_DURATION = CONTAINER_INNER_TIME + CONTAINER_INNER_DURATION;
|
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_TIME = 0.0;
|
||||||
static constexpr double INSTALL_ICONS_FADE_IN_ANIMATION_DURATION = 15.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 SIDE_CONTAINER_WIDTH = CONTAINER_WIDTH / 2.0f;
|
||||||
|
|
||||||
constexpr float BOTTOM_X_GAP = 4.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_WIDTH = 250.0f;
|
||||||
constexpr float CONTAINER_BUTTON_GAP = 9.0f;
|
constexpr float CONTAINER_BUTTON_GAP = 9.0f;
|
||||||
constexpr float BUTTON_HEIGHT = 22.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_appearTime = 0.0;
|
||||||
static double g_disappearTime = DBL_MAX;
|
static double g_disappearTime = DBL_MAX;
|
||||||
static bool g_isDisappearing = false;
|
static bool g_isDisappearing = false;
|
||||||
|
static bool g_isQuitting = false;
|
||||||
|
|
||||||
static std::filesystem::path g_installPath;
|
static std::filesystem::path g_installPath;
|
||||||
static std::filesystem::path g_gameSourcePath;
|
static std::filesystem::path g_gameSourcePath;
|
||||||
@@ -118,6 +120,8 @@ static double g_installerEndTime = DBL_MAX;
|
|||||||
static float g_installerProgressRatioCurrent = 0.0f;
|
static float g_installerProgressRatioCurrent = 0.0f;
|
||||||
static std::atomic<float> g_installerProgressRatioTarget = 0.0f;
|
static std::atomic<float> g_installerProgressRatioTarget = 0.0f;
|
||||||
static std::atomic<bool> g_installerFinished = false;
|
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 bool g_installerFailed = false;
|
||||||
static std::string g_installerErrorMessage;
|
static std::string g_installerErrorMessage;
|
||||||
|
|
||||||
@@ -133,9 +137,17 @@ enum class WizardPage
|
|||||||
InstallFailed,
|
InstallFailed,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class MessagePromptSource
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Next,
|
||||||
|
Back
|
||||||
|
};
|
||||||
|
|
||||||
static WizardPage g_firstPage = WizardPage::SelectLanguage;
|
static WizardPage g_firstPage = WizardPage::SelectLanguage;
|
||||||
static WizardPage g_currentPage = g_firstPage;
|
static WizardPage g_currentPage = g_firstPage;
|
||||||
static std::string g_currentMessagePrompt = "";
|
static std::string g_currentMessagePrompt = "";
|
||||||
|
static MessagePromptSource g_currentMessagePromptSource = MessagePromptSource::Unknown;
|
||||||
static bool g_currentMessagePromptConfirmation = false;
|
static bool g_currentMessagePromptConfirmation = false;
|
||||||
static std::list<std::filesystem::path> g_currentPickerResults;
|
static std::list<std::filesystem::path> g_currentPickerResults;
|
||||||
static std::atomic<bool> g_currentPickerResultsReady = false;
|
static std::atomic<bool> g_currentPickerResultsReady = false;
|
||||||
@@ -151,16 +163,32 @@ static ImVec2 g_joypadAxis = {};
|
|||||||
static int g_currentCursorIndex = -1;
|
static int g_currentCursorIndex = -1;
|
||||||
static int g_currentCursorDefault = 0;
|
static int g_currentCursorDefault = 0;
|
||||||
static bool g_currentCursorAccepted = false;
|
static bool g_currentCursorAccepted = false;
|
||||||
|
static bool g_currentCursorBack = false;
|
||||||
static std::vector<std::pair<ImVec2, ImVec2>> g_currentCursorRects;
|
static std::vector<std::pair<ImVec2, ImVec2>> g_currentCursorRects;
|
||||||
static std::string g_creditsStr;
|
static std::string g_creditsStr;
|
||||||
|
|
||||||
class SDLEventListenerForInstaller : public SDLEventListener
|
class SDLEventListenerForInstaller : public SDLEventListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void OnSDLEvent(SDL_Event *event) override
|
bool OnSDLEvent(SDL_Event *event) override
|
||||||
{
|
{
|
||||||
if (!InstallerWizard::s_isVisible || !g_currentMessagePrompt.empty() || g_currentPickerVisible || !hid::IsInputAllowed())
|
if (!InstallerWizard::s_isVisible)
|
||||||
return;
|
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 AxisValueRange = 32767.0f;
|
||||||
constexpr float AxisTapRange = 0.5f;
|
constexpr float AxisTapRange = 0.5f;
|
||||||
@@ -185,6 +213,9 @@ public:
|
|||||||
case SDL_SCANCODE_KP_ENTER:
|
case SDL_SCANCODE_KP_ENTER:
|
||||||
g_currentCursorAccepted = (g_currentCursorIndex >= 0);
|
g_currentCursorAccepted = (g_currentCursorIndex >= 0);
|
||||||
break;
|
break;
|
||||||
|
case SDL_SCANCODE_ESCAPE:
|
||||||
|
g_currentCursorBack = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -209,6 +240,9 @@ public:
|
|||||||
case SDL_CONTROLLER_BUTTON_A:
|
case SDL_CONTROLLER_BUTTON_A:
|
||||||
g_currentCursorAccepted = (g_currentCursorIndex >= 0);
|
g_currentCursorAccepted = (g_currentCursorIndex >= 0);
|
||||||
break;
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_B:
|
||||||
|
g_currentCursorBack = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -307,6 +341,8 @@ public:
|
|||||||
|
|
||||||
g_currentCursorIndex = newCursorIndex;
|
g_currentCursorIndex = newCursorIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_sdlEventListenerForInstaller;
|
g_sdlEventListenerForInstaller;
|
||||||
@@ -807,15 +843,47 @@ static void DrawDescriptionContainer()
|
|||||||
DrawContainer(sideMin, sideMax, false);
|
DrawContainer(sideMin, sideMax, false);
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
|
|
||||||
if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0)
|
EButtonIcon backIcon;
|
||||||
|
EButtonIcon selectIcon;
|
||||||
|
if (hid::IsInputDeviceController())
|
||||||
{
|
{
|
||||||
auto icon = hid::IsInputDeviceController()
|
backIcon = EButtonIcon::B;
|
||||||
? EButtonIcon::A
|
selectIcon = EButtonIcon::A;
|
||||||
: hid::g_inputDevice == hid::EInputDevice::Keyboard
|
}
|
||||||
? EButtonIcon::Enter
|
else if (hid::g_inputDevice == hid::EInputDevice::Keyboard)
|
||||||
: EButtonIcon::LMB;
|
{
|
||||||
|
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
|
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 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) };
|
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);
|
auto lightSize = Scale(14);
|
||||||
|
|
||||||
DrawButton(min, max, sourceText, true, sourceSet, buttonPressed, (max.x - min.x) - lightSize * 10);
|
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);
|
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)
|
static void DrawProgressBar(float progressRatio)
|
||||||
@@ -965,9 +1034,9 @@ static void DrawProgressBar(float progressRatio)
|
|||||||
float alpha = 1.0;
|
float alpha = 1.0;
|
||||||
const uint32_t innerColor0 = IM_COL32(0, 65, 0, 255 * alpha);
|
const uint32_t innerColor0 = IM_COL32(0, 65, 0, 255 * alpha);
|
||||||
const uint32_t innerColor1 = IM_COL32(0, 32, 0, 255 * alpha);
|
const uint32_t innerColor1 = IM_COL32(0, 32, 0, 255 * alpha);
|
||||||
float xPadding = Scale(6.0f);
|
float xPadding = Scale(4);
|
||||||
float yPadding = Scale(3.0f);
|
float yPadding = Scale(3);
|
||||||
ImVec2 min = { g_aspectRatioOffsetX + Scale(CONTAINER_X) + BOTTOM_X_GAP, g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT + BOTTOM_Y_GAP) };
|
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) };
|
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);
|
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 sliderColor0 = IM_COL32(57, 241, 0, 255 * alpha);
|
||||||
const uint32_t sliderColor1 = IM_COL32(2, 106, 0, 255 * alpha);
|
const uint32_t sliderColor1 = IM_COL32(2, 106, 0, 255 * alpha);
|
||||||
xPadding += Scale(1.0f);
|
xPadding += Scale(1.5f);
|
||||||
yPadding += Scale(1.0f);
|
yPadding += Scale(1.5f);
|
||||||
|
|
||||||
ImVec2 sliderMin = { min.x + xPadding, min.y + yPadding };
|
ImVec2 sliderMin = { min.x + xPadding, min.y + yPadding };
|
||||||
ImVec2 sliderMax = { max.x - xPadding, max.y - yPadding };
|
ImVec2 sliderMax = { max.x - xPadding, max.y - yPadding };
|
||||||
@@ -1177,27 +1246,23 @@ static void DrawSourcePickers()
|
|||||||
std::list<std::filesystem::path> paths;
|
std::list<std::filesystem::path> paths;
|
||||||
if (g_currentPage == WizardPage::SelectGameAndUpdate || g_currentPage == WizardPage::SelectDLC)
|
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");
|
const std::string &addFilesText = Localise("Installer_Button_AddFiles");
|
||||||
float squashRatio;
|
float squashRatio;
|
||||||
ImVec2 textSize = ComputeTextSize(g_dfsogeistdFont, addFilesText.c_str(), 20.0f, squashRatio, ADD_BUTTON_MAX_TEXT_WIDTH);
|
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 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);
|
DrawButton(min, max, addFilesText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
|
||||||
if (buttonPressed)
|
if (buttonPressed)
|
||||||
{
|
{
|
||||||
PickerShow(false);
|
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");
|
const std::string &addFolderText = Localise("Installer_Button_AddFolder");
|
||||||
textSize = ComputeTextSize(g_dfsogeistdFont, addFolderText.c_str(), 20.0f, squashRatio, ADD_BUTTON_MAX_TEXT_WIDTH);
|
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 + BUTTON_TEXT_GAP);
|
||||||
|
|
||||||
max.x = min.x + Scale(textSize.x * squashRatio);
|
|
||||||
DrawButton(min, max, addFolderText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
|
DrawButton(min, max, addFolderText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
|
||||||
if (buttonPressed)
|
if (buttonPressed)
|
||||||
{
|
{
|
||||||
@@ -1227,8 +1292,9 @@ static void DrawInstallingProgress()
|
|||||||
{
|
{
|
||||||
if (g_currentPage == WizardPage::Installing)
|
if (g_currentPage == WizardPage::Installing)
|
||||||
{
|
{
|
||||||
|
constexpr float ProgressSpeed = 0.1f;
|
||||||
float ratioTarget = g_installerProgressRatioTarget.load();
|
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);
|
DrawProgressBar(g_installerProgressRatioCurrent);
|
||||||
|
|
||||||
if (g_installerFinished)
|
if (g_installerFinished)
|
||||||
@@ -1243,8 +1309,14 @@ static void DrawInstallingProgress()
|
|||||||
|
|
||||||
static void InstallerThread()
|
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));
|
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;
|
g_installerFailed = true;
|
||||||
@@ -1254,9 +1326,8 @@ static void InstallerThread()
|
|||||||
Installer::rollback(g_installerJournal);
|
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_installerFinished = true;
|
||||||
|
g_installerCancelled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InstallerStart()
|
static void InstallerStart()
|
||||||
@@ -1297,11 +1368,15 @@ static bool InstallerParseSources(std::string &errorMessage)
|
|||||||
return sourcesParsed;
|
return sourcesParsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawNextButton()
|
static void DrawNavigationButton()
|
||||||
{
|
{
|
||||||
if (g_currentPage != WizardPage::Installing)
|
if (g_currentPage == WizardPage::Installing)
|
||||||
{
|
{
|
||||||
bool nextButtonEnabled = !g_isDisappearing;
|
// 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)
|
if (nextButtonEnabled && g_currentPage == WizardPage::SelectGameAndUpdate)
|
||||||
{
|
{
|
||||||
nextButtonEnabled = !g_gameSourcePath.empty() && !g_updateSourcePath.empty();
|
nextButtonEnabled = !g_gameSourcePath.empty() && !g_updateSourcePath.empty();
|
||||||
@@ -1314,16 +1389,24 @@ static void DrawNextButton()
|
|||||||
}
|
}
|
||||||
|
|
||||||
float squashRatio;
|
float squashRatio;
|
||||||
constexpr float NEXT_BUTTON_MAX_TEXT_WIDTH = 100.0f;
|
constexpr float NAV_BUTTON_MAX_TEXT_WIDTH = 90.0f;
|
||||||
const std::string &buttonText = Localise(skipButton ? "Installer_Button_Skip" : "Installer_Button_Next");
|
const char *nextButtonKey = "Installer_Button_Next";
|
||||||
ImVec2 textSize = ComputeTextSize(g_newRodinFont, buttonText.c_str(), 20.0f, squashRatio, NEXT_BUTTON_MAX_TEXT_WIDTH);
|
if (skipButton)
|
||||||
textSize.x += BUTTON_TEXT_GAP;
|
{
|
||||||
|
nextButtonKey = "Installer_Button_Skip";
|
||||||
|
}
|
||||||
|
else if (g_currentPage == WizardPage::InstallFailed)
|
||||||
|
{
|
||||||
|
nextButtonKey = "Installer_Button_Retry";
|
||||||
|
}
|
||||||
|
|
||||||
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) };
|
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) };
|
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;
|
bool buttonPressed = false;
|
||||||
DrawButton(min, max, buttonText.c_str(), false, nextButtonEnabled, buttonPressed, NEXT_BUTTON_MAX_TEXT_WIDTH);
|
DrawButton(min, max, nextButtonText.c_str(), false, nextButtonEnabled, buttonPressed, NAV_BUTTON_MAX_TEXT_WIDTH);
|
||||||
|
|
||||||
if (buttonPressed)
|
if (buttonPressed)
|
||||||
{
|
{
|
||||||
@@ -1364,6 +1447,7 @@ static void DrawNextButton()
|
|||||||
{
|
{
|
||||||
// Not all the DLC was specified, we show a prompt and await a confirmation before starting the installer.
|
// 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_currentMessagePrompt = Localise("Installer_Message_DLCWarning");
|
||||||
|
g_currentMessagePromptSource = MessagePromptSource::Next;
|
||||||
g_currentMessagePromptConfirmation = true;
|
g_currentMessagePromptConfirmation = true;
|
||||||
}
|
}
|
||||||
else if (skipButton && dlcInstallerMode)
|
else if (skipButton && dlcInstallerMode)
|
||||||
@@ -1396,6 +1480,51 @@ static void DrawNextButton()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawHorizontalBorder(bool bottomBorder)
|
static void DrawHorizontalBorder(bool bottomBorder)
|
||||||
@@ -1491,17 +1620,52 @@ static void DrawMessagePrompt()
|
|||||||
|
|
||||||
if (messageWindowReturned)
|
if (messageWindowReturned)
|
||||||
{
|
{
|
||||||
if (g_currentMessagePromptConfirmation && (g_currentMessageResult == 0) && (g_currentPage == WizardPage::SelectDLC))
|
if (g_currentMessagePromptConfirmation && (g_currentMessageResult == 0))
|
||||||
|
{
|
||||||
|
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.
|
// If user confirms the message prompt that they wish to skip installing the DLC, proceed to the next step.
|
||||||
g_currentPage = WizardPage::CheckSpace;
|
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_currentMessagePrompt.clear();
|
||||||
|
g_currentMessagePromptSource = MessagePromptSource::Unknown;
|
||||||
g_currentMessageResult = -1;
|
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()
|
static void PickerCheckTutorial()
|
||||||
{
|
{
|
||||||
if (!g_pickerTutorialTriggered || !g_currentMessagePrompt.empty())
|
if (!g_pickerTutorialTriggered || !g_currentMessagePrompt.empty())
|
||||||
@@ -1556,7 +1720,7 @@ void InstallerWizard::Init()
|
|||||||
g_pulseInstall = LOAD_ZSTD_TEXTURE(g_pulse_install);
|
g_pulseInstall = LOAD_ZSTD_TEXTURE(g_pulse_install);
|
||||||
g_upHedgeDev = LOAD_ZSTD_TEXTURE(g_hedgedev);
|
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_credits[i];
|
||||||
g_creditsStr += " ";
|
g_creditsStr += " ";
|
||||||
@@ -1579,15 +1743,23 @@ void InstallerWizard::Draw()
|
|||||||
DrawSourcePickers();
|
DrawSourcePickers();
|
||||||
DrawSources();
|
DrawSources();
|
||||||
DrawInstallingProgress();
|
DrawInstallingProgress();
|
||||||
DrawNextButton();
|
DrawNavigationButton();
|
||||||
|
CheckCancelAction();
|
||||||
DrawBorders();
|
DrawBorders();
|
||||||
DrawMessagePrompt();
|
DrawMessagePrompt();
|
||||||
|
PickerDrawForeground();
|
||||||
PickerCheckTutorial();
|
PickerCheckTutorial();
|
||||||
PickerCheckResults();
|
PickerCheckResults();
|
||||||
|
|
||||||
if (g_isDisappearing)
|
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))
|
if (ImGui::GetTime() > (g_disappearTime + disappearDuration))
|
||||||
{
|
{
|
||||||
s_isVisible = false;
|
s_isVisible = false;
|
||||||
@@ -1669,5 +1841,5 @@ bool InstallerWizard::Run(std::filesystem::path installPath, bool skipGame)
|
|||||||
InstallerWizard::Shutdown();
|
InstallerWizard::Shutdown();
|
||||||
EmbeddedPlayer::Shutdown();
|
EmbeddedPlayer::Shutdown();
|
||||||
|
|
||||||
return true;
|
return !g_isQuitting;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ static bool g_isAwaitingResult = false;
|
|||||||
static bool g_isClosing = false;
|
static bool g_isClosing = false;
|
||||||
static bool g_isControlsVisible = false;
|
static bool g_isControlsVisible = false;
|
||||||
|
|
||||||
|
static double g_rowSelectionTime;
|
||||||
static int g_selectedRowIndex;
|
static int g_selectedRowIndex;
|
||||||
|
static int g_prevSelectedRowIndex;
|
||||||
static int g_foregroundCount;
|
static int g_foregroundCount;
|
||||||
|
|
||||||
static bool g_upWasHeld;
|
static bool g_upWasHeld;
|
||||||
@@ -46,10 +48,10 @@ int g_cancelButtonIndex;
|
|||||||
class SDLEventListenerForMessageWindow : public SDLEventListener
|
class SDLEventListenerForMessageWindow : public SDLEventListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void OnSDLEvent(SDL_Event* event) override
|
bool OnSDLEvent(SDL_Event* event) override
|
||||||
{
|
{
|
||||||
if (App::s_isInit || !MessageWindow::s_isVisible || !hid::IsInputAllowed())
|
if (App::s_isInit || !MessageWindow::s_isVisible || !hid::IsInputAllowed())
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
constexpr float axisValueRange = 32767.0f;
|
constexpr float axisValueRange = 32767.0f;
|
||||||
constexpr float axisTapRange = 0.5f;
|
constexpr float axisTapRange = 0.5f;
|
||||||
@@ -140,6 +142,8 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_sdlEventListenerForMessageWindow;
|
g_sdlEventListenerForMessageWindow;
|
||||||
@@ -208,7 +212,13 @@ void DrawButton(int rowIndex, float yOffset, float width, float height, std::str
|
|||||||
bool isSelected = rowIndex == g_selectedRowIndex;
|
bool isSelected = rowIndex == g_selectedRowIndex;
|
||||||
|
|
||||||
if (isSelected)
|
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 fontSize = Scale(28);
|
||||||
auto textSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, text.c_str());
|
auto textSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, text.c_str());
|
||||||
@@ -292,9 +302,9 @@ void MessageWindow::Draw()
|
|||||||
if (Config::Language == ELanguage::Japanese)
|
if (Config::Language == ELanguage::Japanese)
|
||||||
{
|
{
|
||||||
textMarginX -= Scale(2.5f);
|
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 isController = hid::IsInputDeviceController();
|
||||||
@@ -375,6 +385,8 @@ void MessageWindow::Draw()
|
|||||||
bool scrollUp = !g_upWasHeld && upIsHeld;
|
bool scrollUp = !g_upWasHeld && upIsHeld;
|
||||||
bool scrollDown = !g_downWasHeld && downIsHeld;
|
bool scrollDown = !g_downWasHeld && downIsHeld;
|
||||||
|
|
||||||
|
auto prevSelectedRowIndex = g_selectedRowIndex;
|
||||||
|
|
||||||
if (scrollUp)
|
if (scrollUp)
|
||||||
{
|
{
|
||||||
--g_selectedRowIndex;
|
--g_selectedRowIndex;
|
||||||
@@ -391,26 +403,34 @@ void MessageWindow::Draw()
|
|||||||
if (scrollUp || scrollDown)
|
if (scrollUp || scrollDown)
|
||||||
{
|
{
|
||||||
Game_PlaySound("sys_actstg_pausecursor");
|
Game_PlaySound("sys_actstg_pausecursor");
|
||||||
|
g_rowSelectionTime = ImGui::GetTime();
|
||||||
|
g_prevSelectedRowIndex = prevSelectedRowIndex;
|
||||||
g_joypadAxis.y = 0;
|
g_joypadAxis.y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_upWasHeld = upIsHeld;
|
g_upWasHeld = upIsHeld;
|
||||||
g_downWasHeld = downIsHeld;
|
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 =
|
std::array<Button, 2> buttons =
|
||||||
{
|
{
|
||||||
Button(Localise("Common_Select"), EButtonIcon::A),
|
Button(Localise("Common_Select"), selectIcon),
|
||||||
Button(Localise("Common_Back"), EButtonIcon::B),
|
Button(Localise("Common_Back"), backIcon),
|
||||||
};
|
};
|
||||||
|
|
||||||
ButtonGuide::Open(buttons);
|
ButtonGuide::Open(buttons);
|
||||||
}
|
}
|
||||||
else // Only display keyboard prompt during installer.
|
|
||||||
{
|
|
||||||
ButtonGuide::Open(Button(Localise("Common_Select"), EButtonIcon::Enter));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_isDeclined)
|
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)
|
if (g_selectedRowIndex != -1 && g_isAccepted)
|
||||||
|
|||||||
@@ -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 INFO_NARROW_GRID_COUNT = 34.0f;
|
||||||
static constexpr float PADDING_NARROW_GRID_COUNT = 1.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 constexpr int32_t g_categoryCount = 4;
|
||||||
static int32_t g_categoryIndex;
|
static int32_t g_categoryIndex;
|
||||||
static ImVec2 g_categoryAnimMin;
|
static ImVec2 g_categoryAnimMin;
|
||||||
@@ -339,7 +341,7 @@ static float AlignToNextGrid(float value)
|
|||||||
return round(value / GRID_SIZE) * GRID_SIZE;
|
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);
|
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);
|
SetShaderModifier(IMGUI_SHADER_MODIFIER_CHECKERBOARD);
|
||||||
|
|
||||||
drawList->AddRectFilled(min, { min.x + gridSize, max.y }, outerColor); // Container outline left
|
drawList->AddRectFilled({ min.x, min.y + gridSize }, { min.x + gridSize, max.y - gridSize }, outerColor); // Container outline left
|
||||||
drawList->AddRectFilled({ max.x - gridSize, min.y }, max, outerColor); // Container outline right
|
drawList->AddRectFilled({ max.x - gridSize, min.y + gridSize }, { max.x, max.y - gridSize }, drawRightOutline ? outerColor : innerColor); // Container outline right
|
||||||
drawList->AddRectFilled({ min.x + gridSize, min.y }, { max.x - gridSize, min.y + gridSize }, outerColor); // Container outline top
|
drawList->AddRectFilled(min, { max.x, 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, 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
|
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);
|
valueText = fmt::format("{}x{}", GameWindow::s_width, GameWindow::s_height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (config == &Config::Monitor)
|
||||||
|
{
|
||||||
|
valueText = fmt::format("{}", config->Value + 1);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
valueText = fmt::format("{}", config->Value);
|
valueText = fmt::format("{}", config->Value);
|
||||||
@@ -1220,7 +1226,7 @@ static void DrawConfigOptions()
|
|||||||
DrawConfigOption(rowCount++, yOffset, &Config::MotionBlur, true);
|
DrawConfigOption(rowCount++, yOffset, &Config::MotionBlur, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::XboxColorCorrection, true);
|
DrawConfigOption(rowCount++, yOffset, &Config::XboxColorCorrection, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::CutsceneAspectRatio, true);
|
DrawConfigOption(rowCount++, yOffset, &Config::CutsceneAspectRatio, true);
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::UIScaleMode, true);
|
DrawConfigOption(rowCount++, yOffset, &Config::UIAlignmentMode, true);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1239,22 +1245,62 @@ static void DrawConfigOptions()
|
|||||||
|
|
||||||
int32_t prevSelectedRowIndex = g_selectedRowIndex;
|
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)
|
if (scrollUp)
|
||||||
{
|
{
|
||||||
--g_selectedRowIndex;
|
--g_selectedRowIndex;
|
||||||
|
|
||||||
if (g_selectedRowIndex < 0)
|
if (g_selectedRowIndex < 0)
|
||||||
g_selectedRowIndex = rowCount - 1;
|
{
|
||||||
|
g_selectedRowIndex = fastScroll ? 0 : rowCount - 1;
|
||||||
|
fastScrollEncounteredEdge = fastScroll;
|
||||||
|
fastScrollSpeedUp = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (scrollDown)
|
else if (scrollDown)
|
||||||
{
|
{
|
||||||
++g_selectedRowIndex;
|
++g_selectedRowIndex;
|
||||||
|
|
||||||
if (g_selectedRowIndex >= rowCount)
|
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;
|
g_prevSelectedRowIndex = prevSelectedRowIndex;
|
||||||
Game_PlaySound("sys_worldmap_cursor");
|
Game_PlaySound("sys_worldmap_cursor");
|
||||||
}
|
}
|
||||||
@@ -1270,12 +1316,18 @@ static void DrawConfigOptions()
|
|||||||
{
|
{
|
||||||
g_firstVisibleRowIndex = g_selectedRowIndex;
|
g_firstVisibleRowIndex = g_selectedRowIndex;
|
||||||
disableMoveAnimation = true;
|
disableMoveAnimation = true;
|
||||||
|
|
||||||
|
if (g_selectedRowIndex > 0)
|
||||||
|
fastScrollSpeedUp = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_firstVisibleRowIndex + visibleRowCount - 1 < g_selectedRowIndex)
|
if (g_firstVisibleRowIndex + visibleRowCount - 1 < g_selectedRowIndex)
|
||||||
{
|
{
|
||||||
g_firstVisibleRowIndex = std::max(0, g_selectedRowIndex - visibleRowCount + 1);
|
g_firstVisibleRowIndex = std::max(0, g_selectedRowIndex - visibleRowCount + 1);
|
||||||
disableMoveAnimation = true;
|
disableMoveAnimation = true;
|
||||||
|
|
||||||
|
if (g_selectedRowIndex < rowCount - 1)
|
||||||
|
fastScrollSpeedUp = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disableMoveAnimation)
|
if (disableMoveAnimation)
|
||||||
@@ -1310,7 +1362,7 @@ static void DrawSettingsPanel(ImVec2 settingsMin, ImVec2 settingsMax)
|
|||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
SetProceduralOrigin(settingsMin);
|
SetProceduralOrigin(settingsMin);
|
||||||
DrawContainer(settingsMin, settingsMax);
|
DrawContainer(settingsMin, settingsMax, true);
|
||||||
|
|
||||||
if (DrawCategories())
|
if (DrawCategories())
|
||||||
{
|
{
|
||||||
@@ -1334,7 +1386,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
|||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
SetProceduralOrigin(infoMin);
|
SetProceduralOrigin(infoMin);
|
||||||
DrawContainer(infoMin, infoMax);
|
DrawContainer(infoMin, infoMax, false);
|
||||||
|
|
||||||
auto clipRectMin = drawList->GetClipRectMin();
|
auto clipRectMin = drawList->GetClipRectMin();
|
||||||
auto clipRectMax = drawList->GetClipRectMax();
|
auto clipRectMax = drawList->GetClipRectMax();
|
||||||
@@ -1358,7 +1410,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Specialised description for resolution scale
|
// Specialised description for resolution scale.
|
||||||
if (g_selectedItem == &Config::ResolutionScale)
|
if (g_selectedItem == &Config::ResolutionScale)
|
||||||
{
|
{
|
||||||
char buf[100];
|
char buf[100];
|
||||||
@@ -1371,54 +1423,147 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
|||||||
desc = buf;
|
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 fontSize = Scale(28.0f);
|
||||||
auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
|
auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
|
||||||
|
|
||||||
// Extra padding between the start of the description text and the bottom of the thumbnail
|
/* Extra padding between the start
|
||||||
float offsetY = Scale(24.0f);
|
of the description text and the
|
||||||
|
bottom of the thumbnail. */
|
||||||
|
auto offsetY = Scale(24.0f);
|
||||||
|
|
||||||
float textX = clipRectMin.x - Scale(0.5f);
|
auto textX = clipRectMin.x - Scale(0.5f);
|
||||||
float textY = thumbnailMax.y + offsetY;
|
auto textY = thumbnailMax.y + offsetY;
|
||||||
|
|
||||||
if (Config::Language == ELanguage::Japanese)
|
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);
|
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.x -= annotationFontSize;
|
||||||
clipRectMin.y -= annotationFontSize;
|
|
||||||
clipRectMax.x += annotationFontSize;
|
clipRectMax.x += annotationFontSize;
|
||||||
clipRectMax.y += annotationFontSize;
|
|
||||||
|
|
||||||
textY += annotationFontSize;
|
textY += annotationFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto textSize = MeasureCentredParagraph(g_seuratFont, fontSize, clipRectMax.x - clipRectMin.x, 5.0f, desc.c_str());
|
||||||
|
|
||||||
drawList->PushClipRect(clipRectMin, clipRectMax, false);
|
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
|
DrawRubyAnnotatedText
|
||||||
(
|
(
|
||||||
g_seuratFont,
|
g_seuratFont,
|
||||||
fontSize,
|
fontSize,
|
||||||
clipRectMax.x - clipRectMin.x,
|
clipRectMax.x - clipRectMin.x,
|
||||||
{ textX, textY },
|
{ textX, textY - scrollOffset },
|
||||||
5.0f,
|
5.0f,
|
||||||
desc.c_str(),
|
desc.c_str(),
|
||||||
|
|
||||||
[=](const char* str, ImVec2 pos)
|
[=](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)
|
[=](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();
|
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();
|
ResetProceduralOrigin();
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
#include <res/images/options_menu/thumbnails/time_of_day_transition_playstation.dds.h>
|
#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_false.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/transparency_antialiasing_true.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/vertical_camera.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/voice_language.dds.h>
|
#include <res/images/options_menu/thumbnails/voice_language.dds.h>
|
||||||
#include <res/images/options_menu/thumbnails/vibration.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_motionBlurThumbnails[EMotionBlur::Enhanced] = LOAD_ZSTD_TEXTURE(g_motion_blur_enhanced);
|
||||||
|
|
||||||
g_configThumbnails[&Config::XboxColorCorrection] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction);
|
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>
|
template<typename T>
|
||||||
|
|||||||
@@ -67,9 +67,29 @@ void AchievementManager::Unlock(uint16_t id)
|
|||||||
AchievementOverlay::Open(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 = {};
|
Data = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void AchievementManager::Load()
|
||||||
|
{
|
||||||
|
AchievementManager::Reset();
|
||||||
|
|
||||||
Status = EAchStatus::Success;
|
Status = EAchStatus::Success;
|
||||||
|
|
||||||
auto dataPath = GetDataPath(true);
|
auto dataPath = GetDataPath(true);
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ public:
|
|||||||
static size_t GetTotalRecords();
|
static size_t GetTotalRecords();
|
||||||
static bool IsUnlocked(uint16_t id);
|
static bool IsUnlocked(uint16_t id);
|
||||||
static void Unlock(uint16_t id);
|
static void Unlock(uint16_t id);
|
||||||
|
static void UnlockAll();
|
||||||
|
static void Reset();
|
||||||
static void Load();
|
static void Load();
|
||||||
static void Save(bool ignoreStatus = false);
|
static void Save(bool ignoreStatus = false);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -376,11 +376,11 @@ CONFIG_DEFINE_ENUM_TEMPLATE(ECutsceneAspectRatio)
|
|||||||
{ "Unlocked", ECutsceneAspectRatio::Unlocked }
|
{ "Unlocked", ECutsceneAspectRatio::Unlocked }
|
||||||
};
|
};
|
||||||
|
|
||||||
CONFIG_DEFINE_ENUM_TEMPLATE(EUIScaleMode)
|
CONFIG_DEFINE_ENUM_TEMPLATE(EUIAlignmentMode)
|
||||||
{
|
{
|
||||||
{ "Edge", EUIScaleMode::Edge },
|
{ "Edge", EUIAlignmentMode::Edge },
|
||||||
{ "Centre", EUIScaleMode::Centre },
|
{ "Centre", EUIAlignmentMode::Centre },
|
||||||
{ "Center", EUIScaleMode::Centre }
|
{ "Center", EUIAlignmentMode::Centre }
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef CONFIG_DEFINE
|
#undef CONFIG_DEFINE
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ enum class ECutsceneAspectRatio : uint32_t
|
|||||||
Unlocked
|
Unlocked
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EUIScaleMode : uint32_t
|
enum class EUIAlignmentMode : uint32_t
|
||||||
{
|
{
|
||||||
Edge,
|
Edge,
|
||||||
Centre
|
Centre
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ CONFIG_DEFINE_ENUM("Video", EDepthOfFieldQuality, DepthOfFieldQuality, EDepthOfF
|
|||||||
CONFIG_DEFINE_ENUM_LOCALISED("Video", EMotionBlur, MotionBlur, EMotionBlur::Original);
|
CONFIG_DEFINE_ENUM_LOCALISED("Video", EMotionBlur, MotionBlur, EMotionBlur::Original);
|
||||||
CONFIG_DEFINE_LOCALISED("Video", bool, XboxColorCorrection, false);
|
CONFIG_DEFINE_LOCALISED("Video", bool, XboxColorCorrection, false);
|
||||||
CONFIG_DEFINE_ENUM_LOCALISED("Video", ECutsceneAspectRatio, CutsceneAspectRatio, ECutsceneAspectRatio::Original);
|
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, AllowCancellingUnleash, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Exports", bool, DisableAutoSaveWarning, false);
|
CONFIG_DEFINE_HIDDEN("Exports", bool, DisableAutoSaveWarning, false);
|
||||||
|
|||||||
@@ -936,3 +936,24 @@ address = 0x82BADADC
|
|||||||
registers = ["r4", "r5", "r6", "r30"]
|
registers = ["r4", "r5", "r6", "r30"]
|
||||||
jump_address_on_true = 0x82BAD9F0
|
jump_address_on_true = 0x82BAD9F0
|
||||||
jump_address_on_false = 0x82BADAFC
|
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"]
|
||||||
|
|||||||
+1
-1
Submodule UnleashedRecompResources updated: 2d135d175d...3a852c76e5
+1
-1
Submodule tools/XenosRecomp updated: 96458eb7bc...855a5a8c51
Reference in New Issue
Block a user