mirror of
https://github.com/hedge-dev/UnleashedRecomp
synced 2026-06-08 12:28:15 -04:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| db76ffa5b3 | |||
| 7e51a00e3a | |||
| b3d5cdbe3b | |||
| 8ff365cbaa | |||
| d812c12d06 | |||
| 27d4af12ad | |||
| 82f81dc7f9 | |||
| 5f5517977a | |||
| b101e016cf | |||
| de7148772b | |||
| 4d4eba693f | |||
| 08c791f2cf | |||
| 07ad85b7bb | |||
| ba522c0e42 | |||
| 0afd01ff7e | |||
| 5ba4e927ab | |||
| f123ec7083 | |||
| b8ae355915 | |||
| 14faa17cd8 | |||
| 4aeee49561 | |||
| 49cc504ced | |||
| 91f874cbad | |||
| df8234ab3b | |||
| c68b5247c7 | |||
| 910d043f19 | |||
| beac8339c2 | |||
| 02c23384f3 | |||
| 868e0f922a |
@@ -7,9 +7,6 @@
|
||||
[submodule "tools/XenosRecomp"]
|
||||
path = tools/XenosRecomp
|
||||
url = https://github.com/hedge-dev/XenosRecomp.git
|
||||
[submodule "thirdparty/libmspack"]
|
||||
path = thirdparty/libmspack
|
||||
url = https://github.com/kyz/libmspack
|
||||
[submodule "UnleashedRecompResources"]
|
||||
path = UnleashedRecompResources
|
||||
url = https://github.com/hedge-dev/UnleashedRecompResources.git
|
||||
@@ -40,9 +37,6 @@
|
||||
[submodule "thirdparty/concurrentqueue"]
|
||||
path = thirdparty/concurrentqueue
|
||||
url = https://github.com/cameron314/concurrentqueue.git
|
||||
[submodule "thirdparty/tiny-AES-c"]
|
||||
path = thirdparty/tiny-AES-c
|
||||
url = https://github.com/kokke/tiny-AES-c.git
|
||||
[submodule "thirdparty/magic_enum"]
|
||||
path = thirdparty/magic_enum
|
||||
url = https://github.com/Neargye/magic_enum.git
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
```
|
||||
git clone --recurse-submodules https://github.com/hedge-dev/UnleashedRecomp.git
|
||||
```
|
||||
2. Decompress and decrypt `default.xex`, apply the title update patch (`default.xexp`), and place the resulting file in `./UnleashedRecompLib/private/`.
|
||||
2. Place `default.xex` and `default.xexp` in `./UnleashedRecompLib/private/`.
|
||||
3. Decompress `shader.ar` and place the resulting file in `./UnleashedRecompLib/private/`.
|
||||
4. Open the repository directory in Visual Studio 2022 and wait for CMake generation to complete. If you don't plan to debug, switch to the `x64-Clang-Release` configuration.
|
||||
5. Under Solution Explorer, right-click and choose "Switch to CMake Targets View".
|
||||
|
||||
@@ -165,10 +165,8 @@ set(UNLEASHED_RECOMP_UI_CXX_SOURCES
|
||||
set(UNLEASHED_RECOMP_INSTALL_CXX_SOURCES
|
||||
"install/installer.cpp"
|
||||
"install/iso_file_system.cpp"
|
||||
"install/memory_mapped_file.cpp"
|
||||
"install/update_checker.cpp"
|
||||
"install/xcontent_file_system.cpp"
|
||||
"install/xex_patcher.cpp"
|
||||
"install/hashes/apotos_shamar.cpp"
|
||||
"install/hashes/chunnan.cpp"
|
||||
"install/hashes/empire_city_adabat.cpp"
|
||||
@@ -201,8 +199,6 @@ set(UNLEASHED_RECOMP_THIRDPARTY_SOURCES
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot.cpp"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot_demo.cpp"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot/implot_items.cpp"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/libmspack/libmspack/mspack/lzxd.c"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/tiny-AES-c/aes.c"
|
||||
"${UNLEASHED_RECOMP_TOOLS_ROOT}/XenosRecomp/thirdparty/smol-v/source/smolv.cpp"
|
||||
)
|
||||
|
||||
@@ -212,11 +208,8 @@ set(UNLEASHED_RECOMP_THIRDPARTY_INCLUDES
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/json/include"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/libmspack/libmspack/mspack"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/magic_enum/include"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/stb"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/tiny-AES-c"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/TinySHA1"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/unordered_dense/include"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/volk"
|
||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/Vulkan-Headers/include"
|
||||
@@ -500,8 +493,8 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/in
|
||||
|
||||
## Options Menu ##
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/achievement_notifications.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/achievement_notifications.dds" ARRAY_NAME "g_achievement_notifications" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_background_input.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_background_input.dds" ARRAY_NAME "g_allow_background_input" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_dpad_movement.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_dpad_movement.dds" ARRAY_NAME "g_allow_dpad_movement" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_background_input_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_background_input_ps.dds" ARRAY_NAME "g_allow_background_input_ps" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_background_input_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_background_input_xb.dds" ARRAY_NAME "g_allow_background_input_xb" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_none.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_none.dds" ARRAY_NAME "g_antialiasing_none" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_2x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_2x.dds" ARRAY_NAME "g_antialiasing_2x" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_4x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_4x.dds" ARRAY_NAME "g_antialiasing_4x" COMPRESSION_TYPE "zstd")
|
||||
@@ -510,9 +503,9 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/op
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/battle_theme.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/battle_theme.dds" ARRAY_NAME "g_battle_theme" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/brightness.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/brightness.dds" ARRAY_NAME "g_brightness" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/channel_stereo.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/channel_stereo.dds" ARRAY_NAME "g_channel_stereo" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/channel_surround.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/channel_surround.dds" ARRAY_NAME "g_channel_surround" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" ARRAY_NAME "g_control_tutorial_xb" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial_ps.dds" ARRAY_NAME "g_control_tutorial_ps" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/channel_surround.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/channel_surround.dds" ARRAY_NAME "g_channel_surround" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial_ps.dds" ARRAY_NAME "g_control_tutorial_ps" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" ARRAY_NAME "g_control_tutorial_xb" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/controller_icons.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/controller_icons.dds" ARRAY_NAME "g_controller_icons" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/default.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/default.dds" ARRAY_NAME "g_default" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/effects_volume.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/effects_volume.dds" ARRAY_NAME "g_effects_volume" COMPRESSION_TYPE "zstd")
|
||||
@@ -532,23 +525,21 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/op
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/movie_scale_fill.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/movie_scale_fill.dds" ARRAY_NAME "g_movie_scale_fill" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/music_attenuation.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/music_attenuation.dds" ARRAY_NAME "g_music_attenuation" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/music_volume.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/music_volume.dds" ARRAY_NAME "g_music_volume" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/resolution_scale.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/resolution_scale.dds" ARRAY_NAME "g_resolution_scale" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_original.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_original.dds" ARRAY_NAME "g_shadow_resolution_original" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x512.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x512.dds" ARRAY_NAME "g_shadow_resolution_x512" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x1024.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x1024.dds" ARRAY_NAME "g_shadow_resolution_x1024" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x2048.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x2048.dds" ARRAY_NAME "g_shadow_resolution_x2048" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x4096.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x4096.dds" ARRAY_NAME "g_shadow_resolution_x4096" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x8192.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x8192.dds" ARRAY_NAME "g_shadow_resolution_x8192" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/subtitles.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/subtitles.dds" ARRAY_NAME "g_subtitles" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_transition_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_transition_ps.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_transition_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_transition_xb.dds" ARRAY_NAME "g_time_of_day_transition_xbox" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_transition_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_transition_ps.dds" ARRAY_NAME "g_time_of_day_transition_playstation" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/transparency_antialiasing_false.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/transparency_antialiasing_false.dds" ARRAY_NAME "g_transparency_antialiasing_false" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/transparency_antialiasing_true.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/transparency_antialiasing_true.dds" ARRAY_NAME "g_transparency_antialiasing_true" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_alignment_centre.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_alignment_centre.dds" ARRAY_NAME "g_ui_alignment_centre" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_alignment_edge.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_alignment_edge.dds" ARRAY_NAME "g_ui_alignment_edge" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vertical_camera.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vertical_camera.dds" ARRAY_NAME "g_vertical_camera" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/voice_language.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/voice_language.dds" ARRAY_NAME "g_voice_language" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vibration.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration.dds" ARRAY_NAME "g_vibration" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vibration_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration_ps.dds" ARRAY_NAME "g_vibration_ps" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vibration_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration_xb.dds" ARRAY_NAME "g_vibration_xb" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vsync_on.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vsync_on.dds" ARRAY_NAME "g_vsync_on" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vsync_off.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vsync_off.dds" ARRAY_NAME "g_vsync_off" COMPRESSION_TYPE "zstd")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/window_size.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/window_size.dds" ARRAY_NAME "g_window_size" COMPRESSION_TYPE "zstd")
|
||||
|
||||
@@ -60,6 +60,7 @@ PPC_FUNC(sub_822C1130)
|
||||
}
|
||||
|
||||
App::s_deltaTime = ctx.f1.f64;
|
||||
App::s_time += App::s_deltaTime;
|
||||
|
||||
// This function can also be called by the loading thread,
|
||||
// which SDL does not like. To prevent the OS from thinking
|
||||
|
||||
@@ -14,6 +14,7 @@ public:
|
||||
static inline ELanguage s_language;
|
||||
|
||||
static inline double s_deltaTime;
|
||||
static inline double s_time = 0.0; // How much time elapsed since the game started.
|
||||
|
||||
static void Restart(std::vector<std::string> restartArgs = {});
|
||||
static void Exit();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <apu/audio.h>
|
||||
#include <cpu/guest_thread.h>
|
||||
#include <kernel/heap.h>
|
||||
#include <os/logger.h>
|
||||
#include <user/config.h>
|
||||
|
||||
static PPCFunc* g_clientCallback{};
|
||||
@@ -29,6 +30,9 @@ static void CreateAudioDevice()
|
||||
g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0);
|
||||
}
|
||||
|
||||
if (!g_audioDevice)
|
||||
LOGFN_ERROR("Failed to open audio device: {}", SDL_GetError());
|
||||
|
||||
g_downMixToStereo = (obtained.channels == 2);
|
||||
}
|
||||
|
||||
@@ -36,7 +40,13 @@ void XAudioInitializeSystem()
|
||||
{
|
||||
SDL_SetHint(SDL_HINT_AUDIO_CATEGORY, "playback");
|
||||
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "Unleashed Recompiled");
|
||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
|
||||
{
|
||||
LOGFN_ERROR("Failed to init audio subsystem: {}", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
CreateAudioDevice();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,13 @@
|
||||
{ reinterpret_cast<GuestShader*>(0x36DB3B40FA419EF6),reinterpret_cast<GuestShader*>(0x4FDE8FFB7DC1D1CE),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
{ reinterpret_cast<GuestShader*>(0x36DB3B40FA419EF6),reinterpret_cast<GuestShader*>(0xD56D0D7219E51F1D),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x115813F8DBF6CCFF),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x3073F2C856F3333E),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x3382CD5552FAB33C),reinterpret_cast<GuestVertexDeclaration*>(0xB7BBCC93738C9DE4),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x47CDF40D1C605E0D),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x6563290A54293E7A),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x6563290A54293E7A),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x6563290A54293E7A),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x6563290A54293E7A),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x7A8F23548FF778),reinterpret_cast<GuestVertexDeclaration*>(0xC64D046063DE2F63),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x85E3EE1021089A76),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0x933E17818464BC39),reinterpret_cast<GuestVertexDeclaration*>(0xB7BBCC93738C9DE4),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
|
||||
@@ -27,6 +30,7 @@
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0xB8F71746F39A1166),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0xF9F82EC882CD3D08),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x3A4537B51DE9818),reinterpret_cast<GuestShader*>(0xF9F82EC882CD3D08),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x40E4064FE517DFD2),reinterpret_cast<GuestShader*>(0x11958CFF684E1F4B),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
|
||||
{ reinterpret_cast<GuestShader*>(0x4620B236DC38100C),reinterpret_cast<GuestShader*>(0xBBDB735BEACC8F41),reinterpret_cast<GuestVertexDeclaration*>(0x28FD2057B9BD5D1B),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
{ reinterpret_cast<GuestShader*>(0x4620B236DC38100C),reinterpret_cast<GuestShader*>(0xBBDB735BEACC8F41),reinterpret_cast<GuestVertexDeclaration*>(0x2A6D72391BFFFA3C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x4620B236DC38100C),reinterpret_cast<GuestShader*>(0xBBDB735BEACC8F41),reinterpret_cast<GuestVertexDeclaration*>(0x2A6D72391BFFFA3C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
@@ -53,11 +57,13 @@
|
||||
{ reinterpret_cast<GuestShader*>(0x624F608ACB374E12),reinterpret_cast<GuestShader*>(0xA624AF834723B59),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x624F608ACB374E12),reinterpret_cast<GuestShader*>(0xA624AF834723B59),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x624F608ACB374E12),reinterpret_cast<GuestShader*>(0xA624AF834723B59),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x2CA0127E60EB4507),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x2E5AA3C0A9E32751),reinterpret_cast<GuestVertexDeclaration*>(0xB7BBCC93738C9DE4),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x326BB3169FF92317),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x3838E2D27966B21C),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x5A75A52C3F722625),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x86CD1B8641C60EE6),reinterpret_cast<GuestVertexDeclaration*>(0xC64D046063DE2F63),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0x874793F8CC9C7EB0),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xB0F7121362A63137),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xB0F7121362A63137),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xB23ACF01C99C2988),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
@@ -65,6 +71,7 @@
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xC03A891201D4E9E7),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xCE7A73C836F03E6),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xD4D1534DD857403),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xD4D1534DD857403),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xD4D1534DD857403),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xE1748A1E1E38FC5F),reinterpret_cast<GuestVertexDeclaration*>(0x6538EB0019C3A29A),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
|
||||
{ reinterpret_cast<GuestShader*>(0x666E7FB7FCAE0FB7),reinterpret_cast<GuestShader*>(0xE1748A1E1E38FC5F),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
|
||||
@@ -94,6 +101,7 @@
|
||||
{ reinterpret_cast<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x9FA5AACB5B14A226),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
|
||||
{ reinterpret_cast<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0xC47F2F91BA2A5D86),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
|
||||
{ reinterpret_cast<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0xFB79F59782376846),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
|
||||
{ reinterpret_cast<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0xFF42BE2DBCE820C9),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
|
||||
{ reinterpret_cast<GuestShader*>(0x720D6E5EDA78433B),reinterpret_cast<GuestShader*>(0x96EACBACDE1AAFAA),reinterpret_cast<GuestVertexDeclaration*>(0xA81F28FA43A9B511),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
{ reinterpret_cast<GuestShader*>(0x720D6E5EDA78433B),reinterpret_cast<GuestShader*>(0x96EACBACDE1AAFAA),reinterpret_cast<GuestVertexDeclaration*>(0xA81F28FA43A9B511),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 },
|
||||
{ reinterpret_cast<GuestShader*>(0x734799D14CC5177E),reinterpret_cast<GuestShader*>(0xC9978EB328E1066E),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
@@ -104,6 +112,7 @@
|
||||
{ reinterpret_cast<GuestShader*>(0x86FE3502D5EC24AA),reinterpret_cast<GuestShader*>(0x68FCC0B90EBC457B),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 },
|
||||
{ reinterpret_cast<GuestShader*>(0x86FE3502D5EC24AA),reinterpret_cast<GuestShader*>(0x94A71CC9B94E3101),reinterpret_cast<GuestVertexDeclaration*>(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16_FLOAT,RenderFormat::UNKNOWN,1,false,0x0 },
|
||||
{ reinterpret_cast<GuestShader*>(0x88F67387B88F932F),reinterpret_cast<GuestShader*>(0x49101E452DF2FE98),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
{ reinterpret_cast<GuestShader*>(0x8E4BB23465BD909E),reinterpret_cast<GuestShader*>(0x0),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::FRONT,RenderComparisonFunction::LESS_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x0 },
|
||||
{ reinterpret_cast<GuestShader*>(0x8E4BB23465BD909E),reinterpret_cast<GuestShader*>(0x0),reinterpret_cast<GuestVertexDeclaration*>(0xFFFDDC62D86892F1),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS_EQUAL,false,RenderBlendOperation::ADD,1,33554,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_LIST,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x0 },
|
||||
{ reinterpret_cast<GuestShader*>(0x8E4BB23465BD909E),reinterpret_cast<GuestShader*>(0x0),reinterpret_cast<GuestVertexDeclaration*>(0xFFFDDC62D86892F1),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS_EQUAL,false,RenderBlendOperation::ADD,1,33554,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x0 },
|
||||
{ reinterpret_cast<GuestShader*>(0x8EA8F71BA3BE59E7),reinterpret_cast<GuestShader*>(0xA557DD8B24CD2B25),reinterpret_cast<GuestVertexDeclaration*>(0xEC0CD05EE1B1636),false,false,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_LIST,{ 28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::UNKNOWN,1,false,0x10 },
|
||||
@@ -145,6 +154,7 @@
|
||||
{ reinterpret_cast<GuestShader*>(0xA4CF0215A03D9571),reinterpret_cast<GuestShader*>(0xA3A659F1590CC180),reinterpret_cast<GuestVertexDeclaration*>(0x5A2395E29F93DA3C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_FAN,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
{ reinterpret_cast<GuestShader*>(0xA59B07C00039C660),reinterpret_cast<GuestShader*>(0x2E69CC2B4937A698),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0xA59B07C00039C660),reinterpret_cast<GuestShader*>(0xF6FAD0CDA667264),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0xA790E2F622DADAD8),reinterpret_cast<GuestShader*>(0xD56D0D7219E51F1D),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
{ reinterpret_cast<GuestShader*>(0xA7C9D01F7AD3B9D0),reinterpret_cast<GuestShader*>(0x481905CF40E1678D),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 },
|
||||
{ reinterpret_cast<GuestShader*>(0xA7C9D01F7AD3B9D0),reinterpret_cast<GuestShader*>(0x481905CF40E1678D),reinterpret_cast<GuestVertexDeclaration*>(0xC64D046063DE2F63),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0xAC38B793E9C54AC5),reinterpret_cast<GuestShader*>(0x24CAF5A2F1B2AF40),reinterpret_cast<GuestVertexDeclaration*>(0x3CB3EF6B1C43B8C),true,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
@@ -163,6 +173,8 @@
|
||||
{ reinterpret_cast<GuestShader*>(0xBE3AD1D0FE788D2),reinterpret_cast<GuestShader*>(0x4CB3784D7108745F),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0xBE3AD1D0FE788D2),reinterpret_cast<GuestShader*>(0xD57D71ED84D8F864),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0xCF28F33974EC44F6),reinterpret_cast<GuestShader*>(0xD5EA32DB758EF0B8),reinterpret_cast<GuestVertexDeclaration*>(0x7F12180DC3A24B53),true,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 32,24,4,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 },
|
||||
{ reinterpret_cast<GuestShader*>(0xD738D79626374EBE),reinterpret_cast<GuestShader*>(0x47CDF40D1C605E0D),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
{ reinterpret_cast<GuestShader*>(0xD738D79626374EBE),reinterpret_cast<GuestShader*>(0x47CDF40D1C605E0D),reinterpret_cast<GuestVertexDeclaration*>(0xB7BBCC93738C9DE4),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0xD738D79626374EBE),reinterpret_cast<GuestShader*>(0x47CDF40D1C605E0D),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0xD738D79626374EBE),reinterpret_cast<GuestShader*>(0x47CDF40D1C605E0D),reinterpret_cast<GuestVertexDeclaration*>(0xFB4544424558E4C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
|
||||
{ reinterpret_cast<GuestShader*>(0xD738D79626374EBE),reinterpret_cast<GuestShader*>(0x96B8F9FDAAB9B658),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 },
|
||||
@@ -196,6 +208,7 @@
|
||||
{ reinterpret_cast<GuestShader*>(0xECC9C0BD668FE449),reinterpret_cast<GuestShader*>(0x4C4032F88196B450),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0xECC9C0BD668FE449),reinterpret_cast<GuestShader*>(0xC7E2C782C058A625),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0xECC9C0BD668FE449),reinterpret_cast<GuestShader*>(0xFB66DF5D27D3891D),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0xF060DE53CF3B9BB8),reinterpret_cast<GuestShader*>(0xEAADA73091BF526C),reinterpret_cast<GuestVertexDeclaration*>(0xDEB308DCDDF979C7),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 },
|
||||
{ reinterpret_cast<GuestShader*>(0xF066433D33B62D54),reinterpret_cast<GuestShader*>(0xE5256B7D753C9D5F),reinterpret_cast<GuestVertexDeclaration*>(0x3CB3EF6B1C43B8C),true,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
{ reinterpret_cast<GuestShader*>(0xF1D7C544D61D055C),reinterpret_cast<GuestShader*>(0x5A75A52C3F722625),reinterpret_cast<GuestVertexDeclaration*>(0xF10787EFFEEC0153),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 },
|
||||
{ reinterpret_cast<GuestShader*>(0xF58C10092C9EF1AF),reinterpret_cast<GuestShader*>(0x1DD6832FA7E79530),reinterpret_cast<GuestVertexDeclaration*>(0x84BACD816D86543C),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 },
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define IMGUI_SHADER_MODIFIER_TITLE_BEVEL 8
|
||||
#define IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL 9
|
||||
#define IMGUI_SHADER_MODIFIER_RECTANGLE_BEVEL 10
|
||||
#define IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT 11
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
|
||||
@@ -220,6 +220,8 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
|
||||
|
||||
for (size_t i = 0; i < atlas->ConfigData.size(); i++)
|
||||
{
|
||||
double spaceAdvance = 0.0;
|
||||
|
||||
auto& config = atlas->ConfigData[i];
|
||||
bool increaseSpacing = strstr(config.Name, "Seurat") != nullptr;
|
||||
|
||||
@@ -232,8 +234,15 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
|
||||
glyph.getQuadAtlasBounds(u0, v0, u1, v1);
|
||||
|
||||
double advance = glyph.getAdvance();
|
||||
if (increaseSpacing && glyph.getCodepoint() == ' ')
|
||||
advance *= 1.5;
|
||||
if (glyph.getCodepoint() == ' ')
|
||||
{
|
||||
if (increaseSpacing)
|
||||
{
|
||||
advance *= 1.5;
|
||||
}
|
||||
|
||||
spaceAdvance = advance;
|
||||
}
|
||||
|
||||
config.DstFont->AddGlyph(
|
||||
&config,
|
||||
@@ -248,6 +257,39 @@ static bool FontBuilder_Build(ImFontAtlas* atlas)
|
||||
v0 / packer.height,
|
||||
advance);
|
||||
}
|
||||
|
||||
// Used as a zero-width helper for automatic line breaks.
|
||||
// This is useful for languages like Japanese to separate 'words'
|
||||
// so that they don't get split mid-kana by the automatic splitter.
|
||||
config.DstFont->AddGlyph(
|
||||
&config,
|
||||
0x200B,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f);
|
||||
|
||||
// A duplicate of the normal width space character.
|
||||
// Overrides the unicode Four-Per-Em Space character.
|
||||
// This can be used to add visual spacers that are ignored
|
||||
// by the automatic line splitting logic.
|
||||
config.DstFont->AddGlyph(
|
||||
&config,
|
||||
0x2005,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
spaceAdvance);
|
||||
|
||||
config.DstFont->BuildLookupTable();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ struct PushConstants
|
||||
uint GradientBottomLeft;
|
||||
uint ShaderModifier;
|
||||
uint Texture2DDescriptorIndex;
|
||||
float2 DisplaySize;
|
||||
float2 InverseDisplaySize;
|
||||
float2 Origin;
|
||||
float2 Scale;
|
||||
|
||||
@@ -61,10 +61,10 @@ float4 SampleLinear(float2 uvTexspace)
|
||||
|
||||
float4 PixelAntialiasing(float2 uvTexspace)
|
||||
{
|
||||
if ((g_PushConstants.InverseDisplaySize.y / g_PushConstants.InverseDisplaySize.x) >= (4.0 / 3.0))
|
||||
uvTexspace *= g_PushConstants.InverseDisplaySize.y * 720.0f;
|
||||
if ((g_PushConstants.DisplaySize.x * g_PushConstants.InverseDisplaySize.y) >= (4.0 / 3.0))
|
||||
uvTexspace *= g_PushConstants.InverseDisplaySize.y * 720.0;
|
||||
else
|
||||
uvTexspace *= g_PushConstants.InverseDisplaySize.x * 960.0f;
|
||||
uvTexspace *= g_PushConstants.InverseDisplaySize.x * 960.0;
|
||||
|
||||
float2 seam = floor(uvTexspace + 0.5);
|
||||
uvTexspace = (uvTexspace - seam) / fwidth(uvTexspace) + seam;
|
||||
@@ -78,6 +78,51 @@ float median(float r, float g, float b)
|
||||
return max(min(r, g), min(max(r, g), b));
|
||||
}
|
||||
|
||||
float4 SampleSdfFont(float4 color, Texture2D<float4> texture, float2 uv, float2 screenTexSize)
|
||||
{
|
||||
float4 textureColor = texture.Sample(g_SamplerDescriptorHeap[0], uv);
|
||||
|
||||
uint width, height;
|
||||
texture.GetDimensions(width, height);
|
||||
|
||||
float pxRange = 8.0;
|
||||
float2 unitRange = pxRange / float2(width, height);
|
||||
float screenPxRange = max(0.5 * dot(unitRange, screenTexSize), 1.0);
|
||||
|
||||
float sd = median(textureColor.r, textureColor.g, textureColor.b) - 0.5;
|
||||
float screenPxDistance = screenPxRange * (sd + g_PushConstants.Outline / (pxRange * 1.5));
|
||||
|
||||
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TITLE_BEVEL)
|
||||
{
|
||||
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.01)).xy;
|
||||
float3 rimColor = float3(1, 0.8, 0.29);
|
||||
float3 shadowColor = float3(0.84, 0.57, 0);
|
||||
|
||||
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
||||
float3 gradient = lerp(color.rgb, cosTheta >= 0.0 ? rimColor : shadowColor, abs(cosTheta));
|
||||
color.rgb = lerp(gradient, color.rgb, pow(saturate(sd + 0.77), 32.0));
|
||||
}
|
||||
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL)
|
||||
{
|
||||
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.25)).xy;
|
||||
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
||||
float gradient = 1.0 + cosTheta * 0.5;
|
||||
color.rgb = saturate(color.rgb * gradient);
|
||||
}
|
||||
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TEXT_SKEW)
|
||||
{
|
||||
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.5)).xy;
|
||||
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
||||
float gradient = saturate(1.0 + cosTheta);
|
||||
color.rgb = lerp(color.rgb * gradient, color.rgb, pow(saturate(sd + 0.77), 32.0));
|
||||
}
|
||||
|
||||
color.a *= saturate(screenPxDistance + 0.5);
|
||||
color.a *= textureColor.a;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
float4 main(in Interpolators interpolators) : SV_Target
|
||||
{
|
||||
float4 color = interpolators.Color;
|
||||
@@ -86,52 +131,50 @@ float4 main(in Interpolators interpolators) : SV_Target
|
||||
if (g_PushConstants.Texture2DDescriptorIndex != 0)
|
||||
{
|
||||
Texture2D<float4> texture = g_Texture2DDescriptorHeap[g_PushConstants.Texture2DDescriptorIndex & 0x7FFFFFFF];
|
||||
float4 textureColor = texture.Sample(g_SamplerDescriptorHeap[0], interpolators.UV);
|
||||
|
||||
if ((g_PushConstants.Texture2DDescriptorIndex & 0x80000000) != 0)
|
||||
{
|
||||
uint width, height;
|
||||
texture.GetDimensions(width, height);
|
||||
|
||||
float pxRange = 8.0;
|
||||
float2 unitRange = pxRange / float2(width, height);
|
||||
float2 screenTexSize = 1.0 / fwidth(interpolators.UV);
|
||||
float screenPxRange = max(0.5 * dot(unitRange, screenTexSize), 1.0);
|
||||
|
||||
float sd = median(textureColor.r, textureColor.g, textureColor.b) - 0.5;
|
||||
float screenPxDistance = screenPxRange * (sd + g_PushConstants.Outline / (pxRange * 2.0));
|
||||
|
||||
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TITLE_BEVEL)
|
||||
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT)
|
||||
{
|
||||
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.01)).xy;
|
||||
float3 rimColor = float3(1, 0.8, 0.29);
|
||||
float3 shadowColor = float3(0.84, 0.57, 0);
|
||||
|
||||
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
||||
float3 gradient = lerp(color.rgb, cosTheta >= 0.0 ? rimColor : shadowColor, abs(cosTheta));
|
||||
color.rgb = lerp(gradient, color.rgb, pow(saturate(sd + 0.8), 32.0));
|
||||
float scale;
|
||||
float invScale;
|
||||
|
||||
if ((g_PushConstants.DisplaySize.x * g_PushConstants.InverseDisplaySize.y) >= (4.0 / 3.0))
|
||||
{
|
||||
scale = g_PushConstants.InverseDisplaySize.y * 720.0;
|
||||
invScale = g_PushConstants.DisplaySize.y / 720.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
scale = g_PushConstants.InverseDisplaySize.x * 960.0;
|
||||
invScale = g_PushConstants.DisplaySize.x / 960.0;
|
||||
}
|
||||
|
||||
float2 lowQualityPosition = (interpolators.Position.xy - 0.5) * scale;
|
||||
float2 fracPart = frac(lowQualityPosition);
|
||||
|
||||
float2 uvStep = fwidth(interpolators.UV) * invScale;
|
||||
float2 lowQualityUV = interpolators.UV - fracPart * uvStep;
|
||||
float2 screenTexSize = 1.0 / uvStep;
|
||||
|
||||
float4 topLeft = SampleSdfFont(color, texture, lowQualityUV + float2(0, 0), screenTexSize);
|
||||
float4 topRight = SampleSdfFont(color, texture, lowQualityUV + float2(uvStep.x, 0), screenTexSize);
|
||||
float4 bottomLeft = SampleSdfFont(color, texture, lowQualityUV + float2(0, uvStep.y), screenTexSize);
|
||||
float4 bottomRight = SampleSdfFont(color, texture, lowQualityUV + uvStep.xy, screenTexSize);
|
||||
|
||||
float4 top = lerp(topLeft, topRight, fracPart.x);
|
||||
float4 bottom = lerp(bottomLeft, bottomRight, fracPart.x);
|
||||
|
||||
color = lerp(top, bottom, fracPart.y);
|
||||
}
|
||||
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL)
|
||||
else
|
||||
{
|
||||
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.25)).xy;
|
||||
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
||||
float gradient = 1.0 + cosTheta * 0.5;
|
||||
color.rgb = saturate(color.rgb * gradient);
|
||||
color = SampleSdfFont(color, texture, interpolators.UV, 1.0 / fwidth(interpolators.UV));
|
||||
}
|
||||
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TEXT_SKEW)
|
||||
{
|
||||
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.5)).xy;
|
||||
float cosTheta = dot(normal, normalize(float2(1, 1)));
|
||||
float gradient = saturate(1.0 + cosTheta);
|
||||
color.rgb = lerp(color.rgb * gradient, color.rgb, pow(saturate(sd + 0.77), 32.0));
|
||||
}
|
||||
|
||||
color.a *= saturate(screenPxDistance + 0.5);
|
||||
color.a *= textureColor.a;
|
||||
}
|
||||
else
|
||||
{
|
||||
color *= textureColor;
|
||||
color *= texture.Sample(g_SamplerDescriptorHeap[0], interpolators.UV);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -285,6 +285,8 @@ static bool g_vulkan = false;
|
||||
static constexpr bool g_vulkan = true;
|
||||
#endif
|
||||
|
||||
static bool g_mesaTriangleStripWorkaround = false;
|
||||
|
||||
static constexpr bool g_hardwareResolve = true;
|
||||
static constexpr bool g_hardwareDepthResolve = true;
|
||||
|
||||
@@ -1338,6 +1340,7 @@ struct ImGuiPushConstants
|
||||
ImU32 gradientBottomLeft{};
|
||||
uint32_t shaderModifier{};
|
||||
uint32_t texture2DDescriptorIndex{};
|
||||
ImVec2 displaySize{};
|
||||
ImVec2 inverseDisplaySize{};
|
||||
ImVec2 origin{ 0.0f, 0.0f };
|
||||
ImVec2 scale{ 1.0f, 1.0f };
|
||||
@@ -1699,6 +1702,14 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
|
||||
|
||||
g_vulkan = (interfaceFunction == CreateVulkanInterfaceWrapper);
|
||||
#endif
|
||||
|
||||
if (interfaceFunction == CreateVulkanInterfaceWrapper)
|
||||
{
|
||||
// Enable triangle strip workaround if we are on the Mesa RADV driver, as it currently has a bug where
|
||||
// restart indices cause triangles to be culled incorrectly. Converting them to degenerate triangles fixes it.
|
||||
g_mesaTriangleStripWorkaround = deviceDescription.name.find(" (RADV ") != std::string::npos;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2318,6 +2329,7 @@ static void DrawProfiler()
|
||||
ImGui::Text("Present Wait: %s", g_capabilities.presentWait ? "Supported" : "Unsupported");
|
||||
ImGui::Text("Triangle Fan: %s", g_capabilities.triangleFan ? "Supported" : "Unsupported");
|
||||
ImGui::Text("Dynamic Depth Bias: %s", g_capabilities.dynamicDepthBias ? "Supported" : "Unsupported");
|
||||
ImGui::Text("Triangle Strip Workaround: %s", g_mesaTriangleStripWorkaround ? "Enabled" : "Disabled");
|
||||
ImGui::NewLine();
|
||||
|
||||
ImGui::Text("API: %s", g_vulkan ? "Vulkan" : "D3D12");
|
||||
@@ -2485,6 +2497,7 @@ static void ProcDrawImGui(const RenderCommand& cmd)
|
||||
commandList->setViewports(RenderViewport(drawData.DisplayPos.x, drawData.DisplayPos.y, drawData.DisplaySize.x, drawData.DisplaySize.y));
|
||||
|
||||
ImGuiPushConstants pushConstants{};
|
||||
pushConstants.displaySize = drawData.DisplaySize;
|
||||
pushConstants.inverseDisplaySize = { 1.0f / drawData.DisplaySize.x, 1.0f / drawData.DisplaySize.y };
|
||||
commandList->setGraphicsPushConstants(0, &pushConstants);
|
||||
|
||||
@@ -7402,6 +7415,187 @@ bool FxShadowMapMidAsmHook(PPCRegister& r4, PPCRegister& r5, PPCRegister& r6, PP
|
||||
}
|
||||
}
|
||||
|
||||
// There is a driver bug on Mesa where restart indices cause incorrect culling and prevent some triangles from being rendered.
|
||||
// Restart indices can be converted to degenerate triangles as a workaround until this issue gets fixed.
|
||||
static void ConvertToDegenerateTriangles(uint16_t* indices, uint32_t indexCount, uint16_t*& newIndices, uint32_t& newIndexCount)
|
||||
{
|
||||
newIndices = reinterpret_cast<uint16_t*>(g_userHeap.Alloc(indexCount * sizeof(uint16_t) * 3));
|
||||
newIndexCount = 0;
|
||||
|
||||
bool stripStart = true;
|
||||
uint32_t stripSize = 0;
|
||||
uint16_t lastIndex = 0;
|
||||
|
||||
for (uint32_t i = 0; i < indexCount; i++)
|
||||
{
|
||||
uint16_t index = indices[i];
|
||||
if (index == 0xFFFF)
|
||||
{
|
||||
if ((stripSize % 2) != 0)
|
||||
newIndices[newIndexCount++] = lastIndex;
|
||||
|
||||
stripStart = true;
|
||||
stripSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stripStart && newIndexCount != 0)
|
||||
{
|
||||
newIndices[newIndexCount++] = lastIndex;
|
||||
newIndices[newIndexCount++] = index;
|
||||
}
|
||||
|
||||
newIndices[newIndexCount++] = index;
|
||||
stripStart = false;
|
||||
++stripSize;
|
||||
lastIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MeshResource
|
||||
{
|
||||
SWA_INSERT_PADDING(0x4);
|
||||
be<uint32_t> indexCount;
|
||||
be<uint32_t> indices;
|
||||
};
|
||||
|
||||
static std::vector<uint16_t*> g_newIndicesToFree;
|
||||
|
||||
// Hedgehog::Mirage::CMeshData::Make
|
||||
PPC_FUNC_IMPL(__imp__sub_82E44AF8);
|
||||
PPC_FUNC(sub_82E44AF8)
|
||||
{
|
||||
uint16_t* newIndicesToFree = nullptr;
|
||||
|
||||
auto databaseData = reinterpret_cast<Hedgehog::Database::CDatabaseData*>(base + ctx.r3.u32);
|
||||
if (g_mesaTriangleStripWorkaround && !databaseData->IsMadeOne())
|
||||
{
|
||||
auto meshResource = reinterpret_cast<MeshResource*>(base + ctx.r4.u32);
|
||||
|
||||
if (meshResource->indexCount != 0)
|
||||
{
|
||||
uint16_t* newIndices;
|
||||
uint32_t newIndexCount;
|
||||
|
||||
ConvertToDegenerateTriangles(
|
||||
reinterpret_cast<uint16_t*>(base + meshResource->indices),
|
||||
meshResource->indexCount,
|
||||
newIndices,
|
||||
newIndexCount);
|
||||
|
||||
meshResource->indexCount = newIndexCount;
|
||||
meshResource->indices = static_cast<uint32_t>(reinterpret_cast<uint8_t*>(newIndices) - base);
|
||||
|
||||
if (PPC_LOAD_U32(0x83396E98) != NULL)
|
||||
{
|
||||
// If index buffers are getting merged, new indices need to survive until the merge happens.
|
||||
g_newIndicesToFree.push_back(newIndices);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, we can free it immediately.
|
||||
newIndicesToFree = newIndices;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__imp__sub_82E44AF8(ctx, base);
|
||||
|
||||
if (newIndicesToFree != nullptr)
|
||||
g_userHeap.Free(newIndicesToFree);
|
||||
}
|
||||
|
||||
// Hedgehog::Mirage::CShareVertexBuffer::Reset
|
||||
PPC_FUNC_IMPL(__imp__sub_82E250D0);
|
||||
PPC_FUNC(sub_82E250D0)
|
||||
{
|
||||
__imp__sub_82E250D0(ctx, base);
|
||||
|
||||
for (auto newIndicesToFree : g_newIndicesToFree)
|
||||
g_userHeap.Free(newIndicesToFree);
|
||||
|
||||
g_newIndicesToFree.clear();
|
||||
}
|
||||
|
||||
struct LightAndIndexBufferResourceV1
|
||||
{
|
||||
SWA_INSERT_PADDING(0x4);
|
||||
be<uint32_t> indexCount;
|
||||
be<uint32_t> indices;
|
||||
};
|
||||
|
||||
// Hedgehog::Mirage::CLightAndIndexBufferData::MakeV1
|
||||
PPC_FUNC_IMPL(__imp__sub_82E3AFC8);
|
||||
PPC_FUNC(sub_82E3AFC8)
|
||||
{
|
||||
uint16_t* newIndices = nullptr;
|
||||
|
||||
auto databaseData = reinterpret_cast<Hedgehog::Database::CDatabaseData*>(base + ctx.r3.u32);
|
||||
if (g_mesaTriangleStripWorkaround && !databaseData->IsMadeOne())
|
||||
{
|
||||
auto lightAndIndexBufferResource = reinterpret_cast<LightAndIndexBufferResourceV1*>(base + ctx.r4.u32);
|
||||
|
||||
if (lightAndIndexBufferResource->indexCount != 0)
|
||||
{
|
||||
uint32_t newIndexCount;
|
||||
|
||||
ConvertToDegenerateTriangles(
|
||||
reinterpret_cast<uint16_t*>(base + lightAndIndexBufferResource->indices),
|
||||
lightAndIndexBufferResource->indexCount,
|
||||
newIndices,
|
||||
newIndexCount);
|
||||
|
||||
lightAndIndexBufferResource->indexCount = newIndexCount;
|
||||
lightAndIndexBufferResource->indices = static_cast<uint32_t>(reinterpret_cast<uint8_t*>(newIndices) - base);
|
||||
}
|
||||
}
|
||||
|
||||
__imp__sub_82E3AFC8(ctx, base);
|
||||
|
||||
if (newIndices != nullptr)
|
||||
g_userHeap.Free(newIndices);
|
||||
}
|
||||
|
||||
struct LightAndIndexBufferResourceV5
|
||||
{
|
||||
SWA_INSERT_PADDING(0x8);
|
||||
be<uint32_t> indexCount;
|
||||
be<uint32_t> indices;
|
||||
};
|
||||
|
||||
// Hedgehog::Mirage::CLightAndIndexBufferData::MakeV5
|
||||
PPC_FUNC_IMPL(__imp__sub_82E3B1C0);
|
||||
PPC_FUNC(sub_82E3B1C0)
|
||||
{
|
||||
uint16_t* newIndices = nullptr;
|
||||
|
||||
auto databaseData = reinterpret_cast<Hedgehog::Database::CDatabaseData*>(base + ctx.r3.u32);
|
||||
if (g_mesaTriangleStripWorkaround && !databaseData->IsMadeOne())
|
||||
{
|
||||
auto lightAndIndexBufferResource = reinterpret_cast<LightAndIndexBufferResourceV5*>(base + ctx.r4.u32);
|
||||
|
||||
if (lightAndIndexBufferResource->indexCount != 0)
|
||||
{
|
||||
uint32_t newIndexCount;
|
||||
|
||||
ConvertToDegenerateTriangles(
|
||||
reinterpret_cast<uint16_t*>(base + lightAndIndexBufferResource->indices),
|
||||
lightAndIndexBufferResource->indexCount,
|
||||
newIndices,
|
||||
newIndexCount);
|
||||
|
||||
lightAndIndexBufferResource->indexCount = newIndexCount;
|
||||
lightAndIndexBufferResource->indices = static_cast<uint32_t>(reinterpret_cast<uint8_t*>(newIndices) - base);
|
||||
}
|
||||
}
|
||||
|
||||
__imp__sub_82E3B1C0(ctx, base);
|
||||
|
||||
if (newIndices != nullptr)
|
||||
g_userHeap.Free(newIndices);
|
||||
}
|
||||
|
||||
GUEST_FUNCTION_HOOK(sub_82BD99B0, CreateDevice);
|
||||
|
||||
GUEST_FUNCTION_HOOK(sub_82BE6230, DestructResource);
|
||||
|
||||
@@ -598,5 +598,5 @@ XexPatcher::Result Installer::checkGameUpdateCompatibility(const std::filesystem
|
||||
}
|
||||
|
||||
std::vector<uint8_t> patchedBytes;
|
||||
return XexPatcher::apply(xexBytes, patchBytes, patchedBytes, true);
|
||||
return XexPatcher::apply(xexBytes.data(), xexBytes.size(), patchBytes.data(), patchBytes.size(), patchedBytes, true);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <set>
|
||||
|
||||
#include "virtual_file_system.h"
|
||||
#include "xex_patcher.h"
|
||||
#include <xex_patcher.h>
|
||||
|
||||
enum class DLC {
|
||||
Unknown,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "virtual_file_system.h"
|
||||
|
||||
#include "memory_mapped_file.h"
|
||||
#include <memory_mapped_file.h>
|
||||
|
||||
struct ISOFileSystem : VirtualFileSystem
|
||||
{
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
#include "memory_mapped_file.h"
|
||||
|
||||
#if !defined(_WIN32)
|
||||
# include <cstring>
|
||||
# include <cstdio>
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
MemoryMappedFile::MemoryMappedFile()
|
||||
{
|
||||
// Default constructor.
|
||||
}
|
||||
|
||||
MemoryMappedFile::MemoryMappedFile(const std::filesystem::path &path)
|
||||
{
|
||||
open(path);
|
||||
}
|
||||
|
||||
MemoryMappedFile::~MemoryMappedFile()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
MemoryMappedFile::MemoryMappedFile(MemoryMappedFile &&other)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
fileHandle = other.fileHandle;
|
||||
fileMappingHandle = other.fileMappingHandle;
|
||||
fileView = other.fileView;
|
||||
fileSize = other.fileSize;
|
||||
|
||||
other.fileHandle = nullptr;
|
||||
other.fileMappingHandle = nullptr;
|
||||
other.fileView = nullptr;
|
||||
other.fileSize.QuadPart = 0;
|
||||
#else
|
||||
fileHandle = other.fileHandle;
|
||||
fileView = other.fileView;
|
||||
fileSize = other.fileSize;
|
||||
|
||||
other.fileHandle = -1;
|
||||
other.fileView = MAP_FAILED;
|
||||
other.fileSize = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MemoryMappedFile::open(const std::filesystem::path &path)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
fileHandle = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fprintf(stderr, "CreateFileW failed with error %lu.\n", GetLastError());
|
||||
fileHandle = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GetFileSizeEx(fileHandle, &fileSize))
|
||||
{
|
||||
fprintf(stderr, "GetFileSizeEx failed with error %lu.\n", GetLastError());
|
||||
CloseHandle(fileHandle);
|
||||
fileHandle = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
fileMappingHandle = CreateFileMappingW(fileHandle, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
if (fileMappingHandle == nullptr)
|
||||
{
|
||||
fprintf(stderr, "CreateFileMappingW failed with error %lu.\n", GetLastError());
|
||||
CloseHandle(fileHandle);
|
||||
fileHandle = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
fileView = MapViewOfFile(fileMappingHandle, FILE_MAP_READ, 0, 0, 0);
|
||||
if (fileView == nullptr)
|
||||
{
|
||||
fprintf(stderr, "MapViewOfFile failed with error %lu.\n", GetLastError());
|
||||
CloseHandle(fileMappingHandle);
|
||||
CloseHandle(fileHandle);
|
||||
fileMappingHandle = nullptr;
|
||||
fileHandle = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
fileHandle = ::open(path.c_str(), O_RDONLY);
|
||||
if (fileHandle == -1)
|
||||
{
|
||||
fprintf(stderr, "open for %s failed with error %s.\n", path.c_str(), strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
fileSize = lseek(fileHandle, 0, SEEK_END);
|
||||
if (fileSize == (off_t)(-1))
|
||||
{
|
||||
fprintf(stderr, "lseek failed with error %s.\n", strerror(errno));
|
||||
::close(fileHandle);
|
||||
fileHandle = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
fileView = mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fileHandle, 0);
|
||||
if (fileView == MAP_FAILED)
|
||||
{
|
||||
fprintf(stderr, "mmap failed with error %s.\n", strerror(errno));
|
||||
::close(fileHandle);
|
||||
fileHandle = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MemoryMappedFile::close()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if (fileView != nullptr)
|
||||
{
|
||||
UnmapViewOfFile(fileView);
|
||||
}
|
||||
|
||||
if (fileMappingHandle != nullptr)
|
||||
{
|
||||
CloseHandle(fileMappingHandle);
|
||||
}
|
||||
|
||||
if (fileHandle != nullptr)
|
||||
{
|
||||
CloseHandle(fileHandle);
|
||||
}
|
||||
#else
|
||||
if (fileView != MAP_FAILED)
|
||||
{
|
||||
munmap(fileView, fileSize);
|
||||
}
|
||||
|
||||
if (fileHandle != -1)
|
||||
{
|
||||
::close(fileHandle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MemoryMappedFile::isOpen() const
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return (fileView != nullptr);
|
||||
#else
|
||||
return (fileView != MAP_FAILED);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t *MemoryMappedFile::data() const
|
||||
{
|
||||
return reinterpret_cast<uint8_t *>(fileView);
|
||||
}
|
||||
|
||||
size_t MemoryMappedFile::size() const
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return fileSize.QuadPart;
|
||||
#else
|
||||
return static_cast<size_t>(fileSize);
|
||||
#endif
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <Windows.h>
|
||||
#else
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
struct MemoryMappedFile {
|
||||
#if defined(_WIN32)
|
||||
HANDLE fileHandle = nullptr;
|
||||
HANDLE fileMappingHandle = nullptr;
|
||||
LPVOID fileView = nullptr;
|
||||
LARGE_INTEGER fileSize = {};
|
||||
#else
|
||||
int fileHandle = -1;
|
||||
void *fileView = MAP_FAILED;
|
||||
off_t fileSize = 0;
|
||||
#endif
|
||||
|
||||
MemoryMappedFile();
|
||||
MemoryMappedFile(const std::filesystem::path &path);
|
||||
MemoryMappedFile(MemoryMappedFile &&other);
|
||||
~MemoryMappedFile();
|
||||
bool open(const std::filesystem::path &path);
|
||||
void close();
|
||||
bool isOpen() const;
|
||||
uint8_t *data() const;
|
||||
size_t size() const;
|
||||
};
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "virtual_file_system.h"
|
||||
|
||||
#include "memory_mapped_file.h"
|
||||
#include <memory_mapped_file.h>
|
||||
|
||||
enum class XContentVolumeType
|
||||
{
|
||||
|
||||
@@ -1,693 +0,0 @@
|
||||
// Referenced from: https://github.com/xenia-canary/xenia-canary/blob/canary_experimental/src/xenia/cpu/xex_module.cc
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2023 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xex_patcher.h"
|
||||
|
||||
#include <bit>
|
||||
#include <cassert>
|
||||
|
||||
#include <aes.hpp>
|
||||
#include <lzx.h>
|
||||
#include <mspack.h>
|
||||
#include <TinySHA1.hpp>
|
||||
|
||||
#include "memory_mapped_file.h"
|
||||
|
||||
enum Xex2ModuleFlags
|
||||
{
|
||||
XEX_MODULE_MODULE_PATCH = 0x10,
|
||||
XEX_MODULE_PATCH_FULL = 0x20,
|
||||
XEX_MODULE_PATCH_DELTA = 0x40,
|
||||
};
|
||||
|
||||
enum Xex2HeaderKeys
|
||||
{
|
||||
XEX_HEADER_FILE_FORMAT_INFO = 0x3FF,
|
||||
XEX_HEADER_DELTA_PATCH_DESCRIPTOR = 0x5FF,
|
||||
};
|
||||
|
||||
enum Xex2EncryptionType
|
||||
{
|
||||
XEX_ENCRYPTION_NONE = 0,
|
||||
XEX_ENCRYPTION_NORMAL = 1,
|
||||
};
|
||||
|
||||
enum Xex2CompressionType
|
||||
{
|
||||
XEX_COMPRESSION_NONE = 0,
|
||||
XEX_COMPRESSION_BASIC = 1,
|
||||
XEX_COMPRESSION_NORMAL = 2,
|
||||
XEX_COMPRESSION_DELTA = 3,
|
||||
};
|
||||
|
||||
enum Xex2SectionType
|
||||
{
|
||||
XEX_SECTION_CODE = 1,
|
||||
XEX_SECTION_DATA = 2,
|
||||
XEX_SECTION_READONLY_DATA = 3,
|
||||
};
|
||||
|
||||
struct Xex2OptHeader
|
||||
{
|
||||
be<uint32_t> key;
|
||||
|
||||
union
|
||||
{
|
||||
be<uint32_t> value;
|
||||
be<uint32_t> offset;
|
||||
};
|
||||
};
|
||||
|
||||
struct Xex2Header
|
||||
{
|
||||
be<uint32_t> magic;
|
||||
be<uint32_t> moduleFlags;
|
||||
be<uint32_t> headerSize;
|
||||
be<uint32_t> reserved;
|
||||
be<uint32_t> securityOffset;
|
||||
be<uint32_t> headerCount;
|
||||
Xex2OptHeader headers[1];
|
||||
};
|
||||
|
||||
struct Xex2PageDescriptor
|
||||
{
|
||||
union
|
||||
{
|
||||
// Must be endian-swapped before reading the bitfield.
|
||||
uint32_t beValue;
|
||||
struct
|
||||
{
|
||||
uint32_t info : 4;
|
||||
uint32_t pageCount : 28;
|
||||
};
|
||||
};
|
||||
|
||||
char dataDigest[0x14];
|
||||
};
|
||||
|
||||
struct Xex2SecurityInfo
|
||||
{
|
||||
be<uint32_t> headerSize;
|
||||
be<uint32_t> imageSize;
|
||||
char rsaSignature[0x100];
|
||||
be<uint32_t> unknown;
|
||||
be<uint32_t> imageFlags;
|
||||
be<uint32_t> loadAddress;
|
||||
char sectionDigest[0x14];
|
||||
be<uint32_t> importTableCount;
|
||||
char importTableDigest[0x14];
|
||||
char xgd2MediaId[0x10];
|
||||
char aesKey[0x10];
|
||||
be<uint32_t> exportTable;
|
||||
char headerDigest[0x14];
|
||||
be<uint32_t> region;
|
||||
be<uint32_t> allowedMediaTypes;
|
||||
be<uint32_t> pageDescriptorCount;
|
||||
Xex2PageDescriptor pageDescriptors[1];
|
||||
};
|
||||
|
||||
struct Xex2DeltaPatch
|
||||
{
|
||||
be<uint32_t> oldAddress;
|
||||
be<uint32_t> newAddress;
|
||||
be<uint16_t> uncompressedLength;
|
||||
be<uint16_t> compressedLength;
|
||||
char patchData[1];
|
||||
};
|
||||
|
||||
struct Xex2OptDeltaPatchDescriptor
|
||||
{
|
||||
be<uint32_t> size;
|
||||
be<uint32_t> targetVersionValue;
|
||||
be<uint32_t> sourceVersionValue;
|
||||
uint8_t digestSource[0x14];
|
||||
uint8_t imageKeySource[0x10];
|
||||
be<uint32_t> sizeOfTargetHeaders;
|
||||
be<uint32_t> deltaHeadersSourceOffset;
|
||||
be<uint32_t> deltaHeadersSourceSize;
|
||||
be<uint32_t> deltaHeadersTargetOffset;
|
||||
be<uint32_t> deltaImageSourceOffset;
|
||||
be<uint32_t> deltaImageSourceSize;
|
||||
be<uint32_t> deltaImageTargetOffset;
|
||||
Xex2DeltaPatch info;
|
||||
};
|
||||
|
||||
struct Xex2FileBasicCompressionBlock
|
||||
{
|
||||
be<uint32_t> dataSize;
|
||||
be<uint32_t> zeroSize;
|
||||
};
|
||||
|
||||
struct Xex2FileBasicCompressionInfo
|
||||
{
|
||||
Xex2FileBasicCompressionBlock firstBlock;
|
||||
};
|
||||
|
||||
struct Xex2CompressedBlockInfo
|
||||
{
|
||||
be<uint32_t> blockSize;
|
||||
uint8_t blockHash[20];
|
||||
};
|
||||
|
||||
struct Xex2FileNormalCompressionInfo
|
||||
{
|
||||
be<uint32_t> windowSize;
|
||||
Xex2CompressedBlockInfo firstBlock;
|
||||
};
|
||||
|
||||
struct Xex2OptFileFormatInfo
|
||||
{
|
||||
be<uint32_t> infoSize;
|
||||
be<uint16_t> encryptionType;
|
||||
be<uint16_t> compressionType;
|
||||
union
|
||||
{
|
||||
Xex2FileBasicCompressionInfo basic;
|
||||
Xex2FileNormalCompressionInfo normal;
|
||||
} compressionInfo;
|
||||
};
|
||||
|
||||
static const void *getOptHeaderPtr(std::span<const uint8_t> moduleBytes, uint32_t headerKey)
|
||||
{
|
||||
if ((headerKey & 0xFF) == 0)
|
||||
{
|
||||
assert(false && "Wrong type of method for this key. Expected return value is a number.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Xex2Header *xex2Header = (const Xex2Header *)(moduleBytes.data());
|
||||
for (uint32_t i = 0; i < xex2Header->headerCount; i++)
|
||||
{
|
||||
const Xex2OptHeader &optHeader = xex2Header->headers[i];
|
||||
if (optHeader.key == headerKey)
|
||||
{
|
||||
if ((headerKey & 0xFF) == 1)
|
||||
{
|
||||
return &optHeader.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return &moduleBytes.data()[optHeader.offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct mspack_memory_file
|
||||
{
|
||||
mspack_system sys;
|
||||
void *buffer;
|
||||
size_t bufferSize;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
static mspack_memory_file *mspack_memory_open(mspack_system *sys, void *buffer, size_t bufferSize)
|
||||
{
|
||||
assert(bufferSize < INT_MAX);
|
||||
|
||||
if (bufferSize >= INT_MAX)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mspack_memory_file *memoryFile = (mspack_memory_file *)(std::calloc(1, sizeof(mspack_memory_file)));
|
||||
if (memoryFile == nullptr)
|
||||
{
|
||||
return memoryFile;
|
||||
}
|
||||
|
||||
memoryFile->buffer = buffer;
|
||||
memoryFile->bufferSize = bufferSize;
|
||||
memoryFile->offset = 0;
|
||||
return memoryFile;
|
||||
}
|
||||
|
||||
static void mspack_memory_close(mspack_memory_file *file)
|
||||
{
|
||||
std::free(file);
|
||||
}
|
||||
|
||||
static int mspack_memory_read(mspack_file *file, void *buffer, int chars)
|
||||
{
|
||||
mspack_memory_file *memoryFile = (mspack_memory_file *)(file);
|
||||
const size_t remaining = memoryFile->bufferSize - memoryFile->offset;
|
||||
const size_t total = std::min(size_t(chars), remaining);
|
||||
std::memcpy(buffer, (uint8_t *)(memoryFile->buffer) + memoryFile->offset, total);
|
||||
memoryFile->offset += total;
|
||||
return int(total);
|
||||
}
|
||||
|
||||
static int mspack_memory_write(mspack_file *file, void *buffer, int chars)
|
||||
{
|
||||
mspack_memory_file *memoryFile = (mspack_memory_file *)(file);
|
||||
const size_t remaining = memoryFile->bufferSize - memoryFile->offset;
|
||||
const size_t total = std::min(size_t(chars), remaining);
|
||||
std::memcpy((uint8_t *)(memoryFile->buffer) + memoryFile->offset, buffer, total);
|
||||
memoryFile->offset += total;
|
||||
return int(total);
|
||||
}
|
||||
|
||||
static void *mspack_memory_alloc(mspack_system *sys, size_t chars)
|
||||
{
|
||||
return std::calloc(chars, 1);
|
||||
}
|
||||
|
||||
static void mspack_memory_free(void *ptr)
|
||||
{
|
||||
std::free(ptr);
|
||||
}
|
||||
|
||||
static void mspack_memory_copy(void *src, void *dest, size_t chars)
|
||||
{
|
||||
std::memcpy(dest, src, chars);
|
||||
}
|
||||
|
||||
static mspack_system *mspack_memory_sys_create()
|
||||
{
|
||||
auto sys = (mspack_system *)(std::calloc(1, sizeof(mspack_system)));
|
||||
if (!sys)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sys->read = mspack_memory_read;
|
||||
sys->write = mspack_memory_write;
|
||||
sys->alloc = mspack_memory_alloc;
|
||||
sys->free = mspack_memory_free;
|
||||
sys->copy = mspack_memory_copy;
|
||||
return sys;
|
||||
}
|
||||
|
||||
static void mspack_memory_sys_destroy(struct mspack_system *sys)
|
||||
{
|
||||
free(sys);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
inline bool bitScanForward(uint32_t v, uint32_t *outFirstSetIndex)
|
||||
{
|
||||
return _BitScanForward((unsigned long *)(outFirstSetIndex), v) != 0;
|
||||
}
|
||||
|
||||
inline bool bitScanForward(uint64_t v, uint32_t *outFirstSetIndex)
|
||||
{
|
||||
return _BitScanForward64((unsigned long *)(outFirstSetIndex), v) != 0;
|
||||
}
|
||||
|
||||
#else
|
||||
inline bool bitScanForward(uint32_t v, uint32_t *outFirstSetIndex)
|
||||
{
|
||||
int i = ffs(v);
|
||||
*outFirstSetIndex = i - 1;
|
||||
return i != 0;
|
||||
}
|
||||
|
||||
inline bool bitScanForward(uint64_t v, uint32_t *outFirstSetIndex)
|
||||
{
|
||||
int i = __builtin_ffsll(v);
|
||||
*outFirstSetIndex = i - 1;
|
||||
return i != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int lzxDecompress(const void *lzxData, size_t lzxLength, void *dst, size_t dstLength, uint32_t windowSize, void *windowData, size_t windowDataLength)
|
||||
{
|
||||
int resultCode = 1;
|
||||
uint32_t windowBits;
|
||||
if (!bitScanForward(windowSize, &windowBits)) {
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
mspack_system *sys = mspack_memory_sys_create();
|
||||
mspack_memory_file *lzxSrc = mspack_memory_open(sys, (void *)(lzxData), lzxLength);
|
||||
mspack_memory_file *lzxDst = mspack_memory_open(sys, dst, dstLength);
|
||||
lzxd_stream *lzxd = lzxd_init(sys, (mspack_file *)(lzxSrc), (mspack_file *)(lzxDst), windowBits, 0, 0x8000, dstLength, 0);
|
||||
if (lzxd != nullptr) {
|
||||
if (windowData != nullptr) {
|
||||
size_t paddingLength = windowSize - windowDataLength;
|
||||
std::memset(&lzxd->window[0], 0, paddingLength);
|
||||
std::memcpy(&lzxd->window[paddingLength], windowData, windowDataLength);
|
||||
lzxd->ref_data_size = windowSize;
|
||||
}
|
||||
|
||||
resultCode = lzxd_decompress(lzxd, dstLength);
|
||||
lzxd_free(lzxd);
|
||||
}
|
||||
|
||||
if (lzxSrc) {
|
||||
mspack_memory_close(lzxSrc);
|
||||
}
|
||||
|
||||
if (lzxDst) {
|
||||
mspack_memory_close(lzxDst);
|
||||
}
|
||||
|
||||
if (sys) {
|
||||
mspack_memory_sys_destroy(sys);
|
||||
}
|
||||
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
static int lzxDeltaApplyPatch(const Xex2DeltaPatch *deltaPatch, uint32_t patchLength, uint32_t windowSize, uint8_t *dstData)
|
||||
{
|
||||
const void *patchEnd = (const uint8_t *)(deltaPatch) + patchLength;
|
||||
const Xex2DeltaPatch *curPatch = deltaPatch;
|
||||
while (patchEnd > curPatch)
|
||||
{
|
||||
int patchSize = -4;
|
||||
if (curPatch->compressedLength == 0 && curPatch->uncompressedLength == 0 && curPatch->newAddress == 0 && curPatch->oldAddress == 0)
|
||||
{
|
||||
// End of patch.
|
||||
break;
|
||||
}
|
||||
|
||||
switch (curPatch->compressedLength)
|
||||
{
|
||||
case 0:
|
||||
// Set the data to zeroes.
|
||||
std::memset(&dstData[curPatch->newAddress], 0, curPatch->uncompressedLength);
|
||||
break;
|
||||
case 1:
|
||||
// Move the data.
|
||||
std::memcpy(&dstData[curPatch->newAddress], &dstData[curPatch->oldAddress], curPatch->uncompressedLength);
|
||||
break;
|
||||
default:
|
||||
// Decompress the data into the destination.
|
||||
patchSize = curPatch->compressedLength - 4;
|
||||
int result = lzxDecompress(curPatch->patchData, curPatch->compressedLength, &dstData[curPatch->newAddress], curPatch->uncompressedLength, windowSize, &dstData[curPatch->oldAddress], curPatch->uncompressedLength);
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
curPatch++;
|
||||
curPatch = (const Xex2DeltaPatch *)((const uint8_t *)(curPatch) + patchSize);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XexPatcher::Result XexPatcher::apply(std::span<const uint8_t> xexBytes, std::span<const uint8_t> patchBytes, std::vector<uint8_t> &outBytes, bool skipData)
|
||||
{
|
||||
// Validate headers.
|
||||
static const char Xex2Magic[] = "XEX2";
|
||||
const Xex2Header *xexHeader = (const Xex2Header *)(xexBytes.data());
|
||||
if (memcmp(xexBytes.data(), Xex2Magic, 4) != 0)
|
||||
{
|
||||
return Result::XexFileInvalid;
|
||||
}
|
||||
|
||||
const Xex2Header *patchHeader = (const Xex2Header *)(patchBytes.data());
|
||||
if (memcmp(patchBytes.data(), Xex2Magic, 4) != 0)
|
||||
{
|
||||
return Result::PatchFileInvalid;
|
||||
}
|
||||
|
||||
if ((patchHeader->moduleFlags & (XEX_MODULE_MODULE_PATCH | XEX_MODULE_PATCH_DELTA | XEX_MODULE_PATCH_FULL)) == 0)
|
||||
{
|
||||
return Result::PatchFileInvalid;
|
||||
}
|
||||
|
||||
// Validate patch.
|
||||
const Xex2OptDeltaPatchDescriptor *patchDescriptor = (const Xex2OptDeltaPatchDescriptor *)(getOptHeaderPtr(patchBytes, XEX_HEADER_DELTA_PATCH_DESCRIPTOR));
|
||||
if (patchDescriptor == nullptr)
|
||||
{
|
||||
return Result::PatchFileInvalid;
|
||||
}
|
||||
|
||||
const Xex2OptFileFormatInfo *patchFileFormatInfo = (const Xex2OptFileFormatInfo *)(getOptHeaderPtr(patchBytes, XEX_HEADER_FILE_FORMAT_INFO));
|
||||
if (patchFileFormatInfo == nullptr)
|
||||
{
|
||||
return Result::PatchFileInvalid;
|
||||
}
|
||||
|
||||
if (patchFileFormatInfo->compressionType != XEX_COMPRESSION_DELTA)
|
||||
{
|
||||
return Result::PatchFileInvalid;
|
||||
}
|
||||
|
||||
if (patchDescriptor->deltaHeadersSourceOffset > xexHeader->headerSize)
|
||||
{
|
||||
return Result::PatchIncompatible;
|
||||
}
|
||||
|
||||
if (patchDescriptor->deltaHeadersSourceSize > (xexHeader->headerSize - patchDescriptor->deltaHeadersSourceOffset))
|
||||
{
|
||||
return Result::PatchIncompatible;
|
||||
}
|
||||
|
||||
if (patchDescriptor->deltaHeadersTargetOffset > patchDescriptor->sizeOfTargetHeaders)
|
||||
{
|
||||
return Result::PatchIncompatible;
|
||||
}
|
||||
|
||||
uint32_t deltaTargetSize = patchDescriptor->sizeOfTargetHeaders - patchDescriptor->deltaHeadersTargetOffset;
|
||||
if (patchDescriptor->deltaHeadersSourceSize > deltaTargetSize)
|
||||
{
|
||||
return Result::PatchIncompatible;
|
||||
}
|
||||
|
||||
// Apply patch.
|
||||
uint32_t headerTargetSize = patchDescriptor->sizeOfTargetHeaders;
|
||||
if (headerTargetSize == 0)
|
||||
{
|
||||
headerTargetSize = patchDescriptor->deltaHeadersTargetOffset + patchDescriptor->deltaHeadersSourceSize;
|
||||
}
|
||||
|
||||
// Create the bytes for the new XEX header. Copy over the existing data.
|
||||
uint32_t newXexHeaderSize = std::max(headerTargetSize, xexHeader->headerSize.get());
|
||||
outBytes.resize(newXexHeaderSize);
|
||||
memset(outBytes.data(), 0, newXexHeaderSize);
|
||||
memcpy(outBytes.data(), xexBytes.data(), headerTargetSize);
|
||||
|
||||
Xex2Header *newXexHeader = (Xex2Header *)(outBytes.data());
|
||||
if (patchDescriptor->deltaHeadersSourceOffset > 0)
|
||||
{
|
||||
memcpy(&outBytes[patchDescriptor->deltaHeadersTargetOffset], &outBytes[patchDescriptor->deltaHeadersSourceOffset], patchDescriptor->deltaHeadersSourceSize);
|
||||
}
|
||||
|
||||
int resultCode = lzxDeltaApplyPatch(&patchDescriptor->info, patchDescriptor->size, patchFileFormatInfo->compressionInfo.normal.windowSize, outBytes.data());
|
||||
if (resultCode != 0)
|
||||
{
|
||||
return Result::PatchFailed;
|
||||
}
|
||||
|
||||
// Make the header the specified size by the patch.
|
||||
outBytes.resize(headerTargetSize);
|
||||
newXexHeader = (Xex2Header *)(outBytes.data());
|
||||
|
||||
// Copy the rest of the data.
|
||||
const Xex2SecurityInfo *newSecurityInfo = (const Xex2SecurityInfo *)(&outBytes[newXexHeader->securityOffset]);
|
||||
outBytes.resize(outBytes.size() + newSecurityInfo->imageSize);
|
||||
memset(&outBytes[headerTargetSize], 0, outBytes.size() - headerTargetSize);
|
||||
memcpy(&outBytes[headerTargetSize], &xexBytes[xexHeader->headerSize], xexBytes.size() - xexHeader->headerSize);
|
||||
newXexHeader = (Xex2Header *)(outBytes.data());
|
||||
newSecurityInfo = (const Xex2SecurityInfo *)(&outBytes[newXexHeader->securityOffset]);
|
||||
|
||||
// Decrypt the keys and validate that the patch is compatible with the base file.
|
||||
static const uint32_t KeySize = 16;
|
||||
static const uint8_t Xex2RetailKey[16] = { 0x20, 0xB1, 0x85, 0xA5, 0x9D, 0x28, 0xFD, 0xC3, 0x40, 0x58, 0x3F, 0xBB, 0x08, 0x96, 0xBF, 0x91 };
|
||||
static const uint8_t AESBlankIV[AES_BLOCKLEN] = {};
|
||||
const Xex2SecurityInfo *originalSecurityInfo = (const Xex2SecurityInfo *)(&xexBytes[xexHeader->securityOffset]);
|
||||
const Xex2SecurityInfo *patchSecurityInfo = (const Xex2SecurityInfo *)(&patchBytes[patchHeader->securityOffset]);
|
||||
uint8_t decryptedOriginalKey[KeySize];
|
||||
uint8_t decryptedNewKey[KeySize];
|
||||
uint8_t decryptedPatchKey[KeySize];
|
||||
uint8_t decrpytedImageKeySource[KeySize];
|
||||
memcpy(decryptedOriginalKey, originalSecurityInfo->aesKey, KeySize);
|
||||
memcpy(decryptedNewKey, newSecurityInfo->aesKey, KeySize);
|
||||
memcpy(decryptedPatchKey, patchSecurityInfo->aesKey, KeySize);
|
||||
memcpy(decrpytedImageKeySource, patchDescriptor->imageKeySource, KeySize);
|
||||
|
||||
AES_ctx aesContext;
|
||||
AES_init_ctx_iv(&aesContext, Xex2RetailKey, AESBlankIV);
|
||||
AES_CBC_decrypt_buffer(&aesContext, decryptedOriginalKey, KeySize);
|
||||
|
||||
AES_ctx_set_iv(&aesContext, AESBlankIV);
|
||||
AES_CBC_decrypt_buffer(&aesContext, decryptedNewKey, KeySize);
|
||||
|
||||
AES_init_ctx_iv(&aesContext, decryptedNewKey, AESBlankIV);
|
||||
AES_CBC_decrypt_buffer(&aesContext, decryptedPatchKey, KeySize);
|
||||
|
||||
AES_ctx_set_iv(&aesContext, AESBlankIV);
|
||||
AES_CBC_decrypt_buffer(&aesContext, decrpytedImageKeySource, KeySize);
|
||||
|
||||
// Validate the patch's key matches the one from the original XEX.
|
||||
if (memcmp(decrpytedImageKeySource, decryptedOriginalKey, KeySize) != 0)
|
||||
{
|
||||
return Result::PatchIncompatible;
|
||||
}
|
||||
|
||||
// Don't process the rest of the patch.
|
||||
if (skipData)
|
||||
{
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
// Decrypt base XEX if necessary.
|
||||
const Xex2OptFileFormatInfo *fileFormatInfo = (const Xex2OptFileFormatInfo *)(getOptHeaderPtr(xexBytes, XEX_HEADER_FILE_FORMAT_INFO));
|
||||
if (fileFormatInfo == nullptr)
|
||||
{
|
||||
return Result::XexFileInvalid;
|
||||
}
|
||||
|
||||
if (fileFormatInfo->encryptionType == XEX_ENCRYPTION_NORMAL)
|
||||
{
|
||||
AES_init_ctx_iv(&aesContext, decryptedOriginalKey, AESBlankIV);
|
||||
AES_CBC_decrypt_buffer(&aesContext, &outBytes[headerTargetSize], xexBytes.size() - xexHeader->headerSize);
|
||||
}
|
||||
else if (fileFormatInfo->encryptionType != XEX_ENCRYPTION_NONE)
|
||||
{
|
||||
return Result::XexFileInvalid;
|
||||
}
|
||||
|
||||
// Decompress base XEX if necessary.
|
||||
if (fileFormatInfo->compressionType == XEX_COMPRESSION_BASIC)
|
||||
{
|
||||
const Xex2FileBasicCompressionBlock *blocks = &fileFormatInfo->compressionInfo.basic.firstBlock;
|
||||
int32_t numBlocks = (fileFormatInfo->infoSize / sizeof(Xex2FileBasicCompressionBlock)) - 1;
|
||||
int32_t baseCompressedSize = 0;
|
||||
int32_t baseImageSize = 0;
|
||||
for (int32_t i = 0; i < numBlocks; i++) {
|
||||
baseCompressedSize += blocks[i].dataSize;
|
||||
baseImageSize += blocks[i].dataSize + blocks[i].zeroSize;
|
||||
}
|
||||
|
||||
if (outBytes.size() < (headerTargetSize + baseImageSize))
|
||||
{
|
||||
return Result::XexFileInvalid;
|
||||
}
|
||||
|
||||
// Reverse iteration allows to perform this decompression in place.
|
||||
uint8_t *srcDataCursor = outBytes.data() + headerTargetSize + baseCompressedSize;
|
||||
uint8_t *outDataCursor = outBytes.data() + headerTargetSize + baseImageSize;
|
||||
for (int32_t i = numBlocks - 1; i >= 0; i--)
|
||||
{
|
||||
outDataCursor -= blocks[i].zeroSize;
|
||||
memset(outDataCursor, 0, blocks[i].zeroSize);
|
||||
outDataCursor -= blocks[i].dataSize;
|
||||
srcDataCursor -= blocks[i].dataSize;
|
||||
memmove(outDataCursor, srcDataCursor, blocks[i].dataSize);
|
||||
}
|
||||
}
|
||||
else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL || fileFormatInfo->compressionType == XEX_COMPRESSION_DELTA)
|
||||
{
|
||||
return Result::XexFileUnsupported;
|
||||
}
|
||||
else if (fileFormatInfo->compressionType != XEX_COMPRESSION_NONE)
|
||||
{
|
||||
return Result::XexFileInvalid;
|
||||
}
|
||||
|
||||
Xex2OptFileFormatInfo *newFileFormatInfo = (Xex2OptFileFormatInfo *)(getOptHeaderPtr(outBytes, XEX_HEADER_FILE_FORMAT_INFO));
|
||||
if (newFileFormatInfo == nullptr)
|
||||
{
|
||||
return Result::PatchFailed;
|
||||
}
|
||||
|
||||
// Update the header to indicate no encryption or compression is used.
|
||||
newFileFormatInfo->encryptionType = XEX_ENCRYPTION_NONE;
|
||||
newFileFormatInfo->compressionType = XEX_COMPRESSION_NONE;
|
||||
|
||||
// Copy and decrypt patch data if necessary.
|
||||
std::vector<uint8_t> patchData;
|
||||
patchData.resize(patchBytes.size() - patchHeader->headerSize);
|
||||
memcpy(patchData.data(), &patchBytes[patchHeader->headerSize], patchData.size());
|
||||
|
||||
if (patchFileFormatInfo->encryptionType == XEX_ENCRYPTION_NORMAL)
|
||||
{
|
||||
AES_init_ctx_iv(&aesContext, decryptedPatchKey, AESBlankIV);
|
||||
AES_CBC_decrypt_buffer(&aesContext, patchData.data(), patchData.size());
|
||||
}
|
||||
else if (patchFileFormatInfo->encryptionType != XEX_ENCRYPTION_NONE)
|
||||
{
|
||||
return Result::PatchFileInvalid;
|
||||
}
|
||||
|
||||
const Xex2CompressedBlockInfo *currentBlock = &patchFileFormatInfo->compressionInfo.normal.firstBlock;
|
||||
uint8_t *outExe = &outBytes[newXexHeader->headerSize];
|
||||
if (patchDescriptor->deltaImageSourceOffset > 0)
|
||||
{
|
||||
memcpy(&outExe[patchDescriptor->deltaImageTargetOffset], &outExe[patchDescriptor->deltaImageSourceOffset], patchDescriptor->deltaImageSourceSize);
|
||||
}
|
||||
|
||||
static const uint32_t DigestSize = 20;
|
||||
uint8_t sha1Digest[DigestSize];
|
||||
sha1::SHA1 sha1Context;
|
||||
uint8_t *patchDataCursor = patchData.data();
|
||||
while (currentBlock->blockSize > 0)
|
||||
{
|
||||
const Xex2CompressedBlockInfo *nextBlock = (const Xex2CompressedBlockInfo *)(patchDataCursor);
|
||||
|
||||
// Hash and validate the block.
|
||||
sha1Context.reset();
|
||||
sha1Context.processBytes(patchDataCursor, currentBlock->blockSize);
|
||||
sha1Context.finalize(sha1Digest);
|
||||
if (memcmp(sha1Digest, currentBlock->blockHash, DigestSize) != 0)
|
||||
{
|
||||
return Result::PatchFailed;
|
||||
}
|
||||
|
||||
patchDataCursor += 24;
|
||||
|
||||
// Apply the block's patch data.
|
||||
uint32_t blockDataSize = currentBlock->blockSize - 24;
|
||||
if (lzxDeltaApplyPatch((const Xex2DeltaPatch *)(patchDataCursor), blockDataSize, patchFileFormatInfo->compressionInfo.normal.windowSize, outExe) != 0)
|
||||
{
|
||||
return Result::PatchFailed;
|
||||
}
|
||||
|
||||
patchDataCursor += blockDataSize;
|
||||
currentBlock = nextBlock;
|
||||
}
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
XexPatcher::Result XexPatcher::apply(const std::filesystem::path &baseXexPath, const std::filesystem::path &patchXexPath, const std::filesystem::path &newXexPath)
|
||||
{
|
||||
MemoryMappedFile baseXexFile(baseXexPath);
|
||||
MemoryMappedFile patchFile(patchXexPath);
|
||||
if (!baseXexFile.isOpen() || !patchFile.isOpen())
|
||||
{
|
||||
return Result::FileOpenFailed;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> newXexBytes;
|
||||
Result result = apply({ baseXexFile.data(), baseXexFile.size() }, { patchFile.data(), patchFile.size() }, newXexBytes, false);
|
||||
if (result != Result::Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
std::ofstream newXexFile(newXexPath, std::ios::binary);
|
||||
if (!newXexFile.is_open())
|
||||
{
|
||||
return Result::FileOpenFailed;
|
||||
}
|
||||
|
||||
newXexFile.write((const char *)(newXexBytes.data()), newXexBytes.size());
|
||||
newXexFile.close();
|
||||
|
||||
if (newXexFile.bad())
|
||||
{
|
||||
std::filesystem::remove(newXexPath);
|
||||
return Result::FileWriteFailed;
|
||||
}
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Referenced from: https://github.com/xenia-canary/xenia-canary/blob/canary_experimental/src/xenia/cpu/xex_module.cc
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2023 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
struct XexPatcher
|
||||
{
|
||||
enum class Result {
|
||||
Success,
|
||||
FileOpenFailed,
|
||||
FileWriteFailed,
|
||||
XexFileUnsupported,
|
||||
XexFileInvalid,
|
||||
PatchFileInvalid,
|
||||
PatchIncompatible,
|
||||
PatchFailed,
|
||||
PatchUnsupported
|
||||
};
|
||||
|
||||
static Result apply(std::span<const uint8_t> xexBytes, std::span<const uint8_t> patchBytes, std::vector<uint8_t> &outBytes, bool skipData);
|
||||
static Result apply(const std::filesystem::path &baseXexPath, const std::filesystem::path &patchXexPath, const std::filesystem::path &newXexPath);
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
+315
-281
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,6 @@ enum class ELanguage : uint32_t
|
||||
|
||||
inline std::string g_localeMissing = "<missing string>";
|
||||
|
||||
extern std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_locale;
|
||||
extern std::unordered_map<std::string_view, std::unordered_map<ELanguage, std::string>> g_locale;
|
||||
|
||||
std::string& Localise(const char* key);
|
||||
std::string& Localise(const std::string_view& key);
|
||||
|
||||
+19
-19
@@ -106,33 +106,33 @@ uint32_t LdrLoadModule(const std::filesystem::path &path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto* xex = reinterpret_cast<XEX_HEADER*>(loadResult.data());
|
||||
auto security = reinterpret_cast<XEX2_SECURITY_INFO*>((char*)xex + xex->AddressOfSecurityInfo);
|
||||
|
||||
auto format = Xex2FindOptionalHeader<XEX_FILE_FORMAT_INFO>(xex, XEX_HEADER_FILE_FORMAT_INFO);
|
||||
auto entry = *Xex2FindOptionalHeader<uint32_t>(xex, XEX_HEADER_ENTRY_POINT);
|
||||
auto* header = reinterpret_cast<const Xex2Header*>(loadResult.data());
|
||||
auto* security = reinterpret_cast<const Xex2SecurityInfo*>(loadResult.data() + header->securityOffset);
|
||||
const auto* fileFormatInfo = reinterpret_cast<const Xex2OptFileFormatInfo*>(getOptHeaderPtr(loadResult.data(), XEX_HEADER_FILE_FORMAT_INFO));
|
||||
auto entry = *reinterpret_cast<const uint32_t*>(getOptHeaderPtr(loadResult.data(), XEX_HEADER_ENTRY_POINT));
|
||||
ByteSwapInplace(entry);
|
||||
|
||||
auto srcData = (char *)xex + xex->SizeOfHeader;
|
||||
auto destData = (char *)g_memory.Translate(security->ImageBase);
|
||||
if (format->CompressionType == 0)
|
||||
auto srcData = loadResult.data() + header->headerSize;
|
||||
auto destData = reinterpret_cast<uint8_t*>(g_memory.Translate(security->loadAddress));
|
||||
|
||||
if (fileFormatInfo->compressionType == XEX_COMPRESSION_NONE)
|
||||
{
|
||||
memcpy(destData, srcData, security->SizeOfImage);
|
||||
memcpy(destData, srcData, security->imageSize);
|
||||
}
|
||||
else if (format->CompressionType == 1)
|
||||
else if (fileFormatInfo->compressionType == XEX_COMPRESSION_BASIC)
|
||||
{
|
||||
auto numBlocks = (format->SizeOfHeader / sizeof(XEX_BASIC_FILE_COMPRESSION_INFO)) - 1;
|
||||
auto blocks = reinterpret_cast<const XEX_BASIC_FILE_COMPRESSION_INFO*>(format + 1);
|
||||
auto* blocks = reinterpret_cast<const Xex2FileBasicCompressionBlock*>(fileFormatInfo + 1);
|
||||
const size_t numBlocks = (fileFormatInfo->infoSize / sizeof(Xex2FileBasicCompressionInfo)) - 1;
|
||||
|
||||
for (size_t i = 0; i < numBlocks; i++)
|
||||
{
|
||||
memcpy(destData, srcData, blocks[i].SizeOfData);
|
||||
memcpy(destData, srcData, blocks[i].dataSize);
|
||||
|
||||
srcData += blocks[i].SizeOfData;
|
||||
destData += blocks[i].SizeOfData;
|
||||
memset(destData, 0, blocks[i].SizeOfPadding);
|
||||
srcData += blocks[i].dataSize;
|
||||
destData += blocks[i].dataSize;
|
||||
|
||||
destData += blocks[i].SizeOfPadding;
|
||||
memset(destData, 0, blocks[i].zeroSize);
|
||||
destData += blocks[i].zeroSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -140,9 +140,9 @@ uint32_t LdrLoadModule(const std::filesystem::path &path)
|
||||
assert(false && "Unknown compression type.");
|
||||
}
|
||||
|
||||
auto res = Xex2FindOptionalHeader<XEX_RESOURCE_INFO>(xex, XEX_HEADER_RESOURCE_INFO);
|
||||
auto res = reinterpret_cast<const Xex2ResourceInfo*>(getOptHeaderPtr(loadResult.data(), XEX_HEADER_RESOURCE_INFO));
|
||||
|
||||
g_xdbfWrapper = XDBFWrapper((uint8_t*)g_memory.Translate(res->Offset.get()), res->SizeOfData);
|
||||
g_xdbfWrapper = XDBFWrapper((uint8_t*)g_memory.Translate(res->offset.get()), res->sizeOfData);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -562,14 +562,68 @@ PPC_FUNC(sub_82E0D3E8)
|
||||
g_userHeap.Free(newArlFileData);
|
||||
}
|
||||
|
||||
// Load elements have an unused "pretty name" field. We will use this field to store the archive file path,
|
||||
// prefixed with a magic string. When the first load detects this string, it will load append archives
|
||||
// and then clear the field to prevent remaining splits from loading the append archives again.
|
||||
// We cannot rely on .ar.00 being the first split to be loaded, so this approach is necessary.
|
||||
static thread_local uint32_t g_prefixedArFilePath = NULL;
|
||||
|
||||
// Hedgehog::Database::CDatabaseLoader::LoadArchives
|
||||
PPC_FUNC_IMPL(__imp__sub_82E0CC38);
|
||||
PPC_FUNC(sub_82E0CC38)
|
||||
{
|
||||
if (g_mods.empty())
|
||||
{
|
||||
__imp__sub_82E0CC38(ctx, base);
|
||||
return;
|
||||
}
|
||||
|
||||
auto r3 = ctx.r3;
|
||||
auto r4 = ctx.r4;
|
||||
auto r5 = ctx.r5;
|
||||
auto r6 = ctx.r6;
|
||||
auto r7 = ctx.r7;
|
||||
auto r8 = ctx.r8;
|
||||
|
||||
const char* arFilePath = reinterpret_cast<const char*>(base + PPC_LOAD_U32(r5.u32));
|
||||
|
||||
// __HH_ALLOC
|
||||
ctx.r3.u32 = 22 + strlen(arFilePath);
|
||||
sub_822C0988(ctx, base);
|
||||
char* prefixedArFilePath = reinterpret_cast<char*>(base + ctx.r3.u32);
|
||||
|
||||
*reinterpret_cast<be<uint32_t>*>(prefixedArFilePath) = 1;
|
||||
strcpy(prefixedArFilePath + 0x4, "/UnleashedRecomp/");
|
||||
strcpy(prefixedArFilePath + 0x15, arFilePath);
|
||||
|
||||
ctx.r1.u32 -= 0x10;
|
||||
uint32_t stackSpace = ctx.r1.u32;
|
||||
PPC_STORE_U32(stackSpace, static_cast<uint32_t>(reinterpret_cast<uint8_t*>(prefixedArFilePath) - base) + 0x4);
|
||||
g_prefixedArFilePath = stackSpace;
|
||||
|
||||
ctx.r3 = r3;
|
||||
ctx.r4 = r4;
|
||||
ctx.r5 = r5;
|
||||
ctx.r6 = r6;
|
||||
ctx.r7 = r7;
|
||||
ctx.r8 = r8;
|
||||
__imp__sub_82E0CC38(ctx, base);
|
||||
|
||||
// Hedgehog::Base::CSharedString::~CSharedString
|
||||
ctx.r3.u32 = stackSpace;
|
||||
sub_82DFB148(ctx, base);
|
||||
|
||||
g_prefixedArFilePath = NULL;
|
||||
ctx.r1.u32 += 0x10;
|
||||
}
|
||||
|
||||
// Hedgehog::Database::SLoadElement::SLoadElement
|
||||
PPC_FUNC_IMPL(__imp__sub_82E140D8);
|
||||
PPC_FUNC(sub_82E140D8)
|
||||
{
|
||||
// Store archive name as the pretty name to use it later for append archive loading.
|
||||
// This is always set to an empty string for archives, so it should be safe to replace.
|
||||
if (!g_mods.empty() && PPC_LOAD_U32(ctx.r5.u32) == 0x8200A621)
|
||||
ctx.r5.u32 = ctx.r6.u32;
|
||||
// Store the prefixed archive file path as the pretty name. It's unused for archives we want to append to.
|
||||
if (!g_mods.empty() && PPC_LOAD_U32(ctx.r5.u32) == 0x8200A621 && g_prefixedArFilePath != NULL)
|
||||
ctx.r5.u32 = g_prefixedArFilePath;
|
||||
|
||||
__imp__sub_82E140D8(ctx, base);
|
||||
}
|
||||
@@ -584,25 +638,17 @@ PPC_FUNC(sub_82E0B500)
|
||||
return;
|
||||
}
|
||||
|
||||
std::u8string_view arFilePathU8(reinterpret_cast<const char8_t*>(base + PPC_LOAD_U32(ctx.r5.u32)));
|
||||
size_t index = arFilePathU8.find(u8".ar.00");
|
||||
if (index == (arFilePathU8.size() - 6))
|
||||
uint32_t prefixedArFilePath = PPC_LOAD_U32(ctx.r5.u32);
|
||||
std::u8string_view arFilePathU8(reinterpret_cast<const char8_t*>(base + prefixedArFilePath));
|
||||
if (!arFilePathU8.starts_with(u8"/UnleashedRecomp/"))
|
||||
{
|
||||
arFilePathU8.remove_suffix(3);
|
||||
__imp__sub_82E0B500(ctx, base);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = arFilePathU8.find(u8".ar");
|
||||
|
||||
if (index != (arFilePathU8.size() - 3) ||
|
||||
arFilePathU8.starts_with(u8"tg-") ||
|
||||
arFilePathU8.starts_with(u8"gia-") ||
|
||||
arFilePathU8.starts_with(u8"gi-texture-"))
|
||||
{
|
||||
__imp__sub_82E0B500(ctx, base);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Immediately clear the string, so the remaining splits don't load append archives again.
|
||||
PPC_STORE_U8(prefixedArFilePath, 0x00);
|
||||
arFilePathU8.remove_prefix(0x11);
|
||||
|
||||
auto r3 = ctx.r3; // Callback
|
||||
auto r4 = ctx.r4; // Database
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <os/registry.h>
|
||||
#include <unordered_map>
|
||||
|
||||
inline const wchar_t* g_registryRoot = L"Software\\UnleashedRecomp";
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ PPC_FUNC(sub_824B0930)
|
||||
|
||||
if (*SWA::SGlobals::ms_IsRenderHud && pHudPause->m_IsShown && !pHudPause->m_Submenu && pHudPause->m_Transition == SWA::eTransitionType_Undefined)
|
||||
{
|
||||
ButtonGuide::Open(Button("Achievements_Name", EButtonIcon::Back, EButtonAlignment::Left, EFontQuality::Low));
|
||||
ButtonGuide::Open(Button("Achievements_Name", FLT_MAX, EButtonIcon::Back, EButtonAlignment::Left, EFontQuality::Low));
|
||||
g_isClosed = false;
|
||||
}
|
||||
else if (!g_isClosed)
|
||||
|
||||
@@ -70,10 +70,9 @@ void ObjBigBarrelSetPositionMidAsmHook(PPCRegister& r3, PPCRegister& r4)
|
||||
}
|
||||
}
|
||||
|
||||
// SWA::CExBullet::AddCallback
|
||||
// Tornado Defense bullet particles are colored by the button prompt, which differs on PlayStation 3.
|
||||
// Luckily, the PS3 particles are left in the files, and they get spawned by name when a bullet gets created.
|
||||
|
||||
// SWA::CExBullet::AddCallback
|
||||
PPC_FUNC_IMPL(__imp__sub_82B14CC0);
|
||||
PPC_FUNC(sub_82B14CC0)
|
||||
{
|
||||
@@ -99,3 +98,38 @@ PPC_FUNC(sub_82B14CC0)
|
||||
|
||||
__imp__sub_82B14CC0(ctx, base);
|
||||
}
|
||||
|
||||
// CObjGrindDashPanel is particularly egregious when it comes to overlapping sounds at HFR
|
||||
// due to the character proxy sending the hit message multiple times in a frame. This is a
|
||||
// quick workaround to limit the message process function to occur at a 30 FPS time step.
|
||||
static constexpr size_t OBJ_GRIND_DASH_PANEL_SIZE = 0x160;
|
||||
|
||||
void ObjGrindDashPanelAllocMidAsmHook(PPCRegister& r3)
|
||||
{
|
||||
r3.u32 += sizeof(double);
|
||||
}
|
||||
|
||||
// SWA::CObjGrindDashPanel::CObjGrindDashPanel
|
||||
PPC_FUNC_IMPL(__imp__sub_82614228);
|
||||
PPC_FUNC(sub_82614228)
|
||||
{
|
||||
*reinterpret_cast<double*>(base + ctx.r3.u32 + OBJ_GRIND_DASH_PANEL_SIZE) = 0.0;
|
||||
__imp__sub_82614228(ctx, base);
|
||||
}
|
||||
|
||||
// SWA::CObjGrindDashPanel::MsgHitEventCollision::Impl
|
||||
PPC_FUNC_IMPL(__imp__sub_826145D8);
|
||||
PPC_FUNC(sub_826145D8)
|
||||
{
|
||||
constexpr double REFERENCE_DELTA_TIME = 1.0 / 30.0;
|
||||
constexpr double DELTA_TIME_TOLERANCE = 0.0001;
|
||||
|
||||
auto lastHitTime = reinterpret_cast<double*>(base + ctx.r3.u32 + OBJ_GRIND_DASH_PANEL_SIZE);
|
||||
auto deltaTime = App::s_time - *lastHitTime;
|
||||
|
||||
if ((deltaTime + DELTA_TIME_TOLERANCE) > REFERENCE_DELTA_TIME)
|
||||
{
|
||||
__imp__sub_826145D8(ctx, base);
|
||||
*lastHitTime = App::s_time;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
inline std::array<const char*, 14> g_credits =
|
||||
inline std::array<const char*, 17> g_credits =
|
||||
{
|
||||
"Skyth",
|
||||
"Hyper",
|
||||
@@ -15,5 +15,8 @@ inline std::array<const char*, 14> g_credits =
|
||||
"LadyLunanova",
|
||||
"LJSTAR",
|
||||
"Goalringmod27",
|
||||
"M&M"
|
||||
"M&M",
|
||||
"DaGuAr",
|
||||
"brianuuuSonic",
|
||||
"Kitzuku"
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION_MILESTONE="Beta 3"
|
||||
VERSION_MILESTONE="Release Candidate 1"
|
||||
VERSION_MAJOR=1
|
||||
VERSION_MINOR=0
|
||||
VERSION_REVISION=0
|
||||
|
||||
@@ -763,7 +763,7 @@ void AchievementMenu::Open()
|
||||
return std::get<1>(a) > std::get<1>(b);
|
||||
});
|
||||
|
||||
ButtonGuide::Open(Button("Common_Back", EButtonIcon::B));
|
||||
ButtonGuide::Open(Button("Common_Back", FLT_MAX, EButtonIcon::B, EFontQuality::Low));
|
||||
|
||||
ResetSelection();
|
||||
Game_PlaySound("sys_actstg_pausewinopen");
|
||||
|
||||
@@ -183,6 +183,9 @@ void AchievementOverlay::Draw()
|
||||
IM_COL32(255, 255, 255, 255) // col
|
||||
);
|
||||
|
||||
// Use low quality text.
|
||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
|
||||
|
||||
// Draw header text.
|
||||
DrawTextWithShadow
|
||||
(
|
||||
@@ -208,6 +211,9 @@ void AchievementOverlay::Draw()
|
||||
1.0f, // radius
|
||||
IM_COL32(0, 0, 0, 255) // shadowColour
|
||||
);
|
||||
|
||||
// Reset low quality text shader modifier.
|
||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
constexpr float DEFAULT_SIDE_MARGINS = 379;
|
||||
|
||||
ImFont* g_fntNewRodin;
|
||||
ImFont* g_fntNewRodinLQ;
|
||||
|
||||
std::unique_ptr<GuestTexture> g_upControllerIcons;
|
||||
std::unique_ptr<GuestTexture> g_upKBMIcons;
|
||||
@@ -144,79 +143,74 @@ std::tuple<std::tuple<ImVec2, ImVec2>, GuestTexture*> GetButtonIcon(EButtonIcon
|
||||
return std::make_tuple(btn, texture);
|
||||
}
|
||||
|
||||
ImFont* GetFont(EFontQuality fontQuality)
|
||||
{
|
||||
return fontQuality == EFontQuality::Low
|
||||
? g_fntNewRodinLQ
|
||||
: g_fntNewRodin;
|
||||
}
|
||||
|
||||
static void DrawGuide(float* offset, ImVec2 regionMin, ImVec2 regionMax, EButtonIcon icon,
|
||||
EButtonAlignment alignment, ImVec2 iconMin, ImVec2 iconMax, EFontQuality fontQuality,
|
||||
ImVec2 textSize, float fontSize, const char* text)
|
||||
float textWidth, float maxTextWidth, float textScale, float fontSize, const char* text)
|
||||
{
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
auto _icon = icon;
|
||||
auto iconWidth = Scale(g_iconWidths[icon]);
|
||||
auto dualIconMarginX = Scale(25);
|
||||
auto textMarginY = regionMin.y + Scale(9.0f);
|
||||
|
||||
if (icon == EButtonIcon::LBRB)
|
||||
{
|
||||
_icon = EButtonIcon::LB;
|
||||
}
|
||||
else if (icon == EButtonIcon::LTRT)
|
||||
{
|
||||
_icon = EButtonIcon::LT;
|
||||
}
|
||||
else
|
||||
{
|
||||
dualIconMarginX = 0;
|
||||
}
|
||||
ImVec2 textPos;
|
||||
|
||||
if (icon == EButtonIcon::LBRB || icon == EButtonIcon::LTRT)
|
||||
{
|
||||
iconMin = alignment == EButtonAlignment::Left
|
||||
? ImVec2(/* X */ regionMin.x + *offset - dualIconMarginX * 3, /* Y */ iconMin.y)
|
||||
: ImVec2(/* X */ regionMax.x - *offset - textSize.x - iconWidth, /* Y */ iconMin.y);
|
||||
auto iconMarginX = Scale(16);
|
||||
|
||||
iconMax = alignment == EButtonAlignment::Left
|
||||
? ImVec2(iconMin.x + iconWidth, iconMax.y)
|
||||
: ImVec2(iconMin.x, iconMax.y);
|
||||
}
|
||||
iconMin.x = alignment == EButtonAlignment::Left
|
||||
? regionMin.x + *offset - maxTextWidth + (iconWidth / 2)
|
||||
: regionMax.x - *offset - maxTextWidth - (iconWidth / 2) - iconMarginX;
|
||||
|
||||
auto btnIcon = GetButtonIcon(_icon);
|
||||
drawList->AddImage(std::get<1>(btnIcon), iconMin, iconMax, GET_UV_COORDS(std::get<0>(btnIcon)));
|
||||
iconMax.x = iconMin.x + iconWidth;
|
||||
|
||||
auto font = GetFont(fontQuality);
|
||||
|
||||
auto textMarginX = alignment == EButtonAlignment::Left
|
||||
? regionMin.x + *offset + dualIconMarginX
|
||||
: regionMax.x - *offset - dualIconMarginX * 2;
|
||||
|
||||
auto textMarginY = regionMin.y + Scale(8);
|
||||
|
||||
ImVec2 textPosition = { textMarginX, textMarginY };
|
||||
|
||||
DrawTextWithOutline(font, fontSize, textPosition, IM_COL32_WHITE, text, 4, IM_COL32_BLACK);
|
||||
|
||||
// Add extra luminance to low quality text.
|
||||
if (fontQuality == EFontQuality::Low)
|
||||
drawList->AddText(font, fontSize, textPosition, IM_COL32(255, 255, 255, 127), text);
|
||||
|
||||
if (icon == EButtonIcon::LBRB || icon == EButtonIcon::LTRT)
|
||||
{
|
||||
auto btnIcon = GetButtonIcon(icon == EButtonIcon::LBRB ? EButtonIcon::RB : EButtonIcon::RT);
|
||||
// Left button.
|
||||
auto btnIcon = GetButtonIcon(icon == EButtonIcon::LBRB ? EButtonIcon::LB : EButtonIcon::LT);
|
||||
drawList->AddImage(std::get<1>(btnIcon), iconMin, iconMax, GET_UV_COORDS(std::get<0>(btnIcon)));
|
||||
|
||||
auto dualIconMin = alignment == EButtonAlignment::Left
|
||||
? ImVec2(/* X */ regionMin.x + *offset + textSize.x + dualIconMarginX * 2, /* Y */ iconMin.y)
|
||||
: ImVec2(/* X */ regionMax.x - *offset + textSize.x - dualIconMarginX, /* Y */ iconMin.y);
|
||||
? ImVec2(iconMax.x + maxTextWidth + iconMarginX, iconMin.y)
|
||||
: ImVec2(regionMax.x - *offset + maxTextWidth - iconWidth, iconMin.y);
|
||||
|
||||
auto dualIconMax = ImVec2(dualIconMin.x + iconWidth, iconMax.y);
|
||||
|
||||
// Right button.
|
||||
btnIcon = GetButtonIcon(icon == EButtonIcon::LBRB ? EButtonIcon::RB : EButtonIcon::RT);
|
||||
drawList->AddImage(std::get<1>(btnIcon), dualIconMin, dualIconMax, GET_UV_COORDS(std::get<0>(btnIcon)));
|
||||
|
||||
*offset += dualIconMarginX + iconWidth;
|
||||
textPos = { (iconMax.x + ((dualIconMin.x - iconMax.x) - maxTextWidth + std::max(0.0f, maxTextWidth - textWidth)) / 2) + Scale(2), textMarginY};
|
||||
|
||||
*offset += iconWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto btnIcon = GetButtonIcon(icon);
|
||||
|
||||
drawList->AddImage(std::get<1>(btnIcon), iconMin, iconMax, GET_UV_COORDS(std::get<0>(btnIcon)));
|
||||
|
||||
auto textMarginX = alignment == EButtonAlignment::Left
|
||||
? regionMin.x + *offset
|
||||
: regionMax.x - *offset;
|
||||
|
||||
textPos = { textMarginX, textMarginY };
|
||||
}
|
||||
|
||||
SetScale({ textScale, 1.0f });
|
||||
SetOrigin(textPos);
|
||||
|
||||
if (fontQuality == EFontQuality::Low)
|
||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
|
||||
|
||||
DrawTextWithOutline(g_fntNewRodin, fontSize, textPos, IM_COL32_WHITE, text, 4, IM_COL32_BLACK);
|
||||
|
||||
if (fontQuality == EFontQuality::Low)
|
||||
{
|
||||
// Add extra luminance to low quality text.
|
||||
drawList->AddText(g_fntNewRodin, fontSize, textPos, IM_COL32(255, 255, 255, 127), text);
|
||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
|
||||
}
|
||||
|
||||
SetScale({ 1.0f, 1.0f });
|
||||
SetOrigin({ 0.0f, 0.0f });
|
||||
}
|
||||
|
||||
void ButtonGuide::Init()
|
||||
@@ -224,8 +218,6 @@ void ButtonGuide::Init()
|
||||
auto& io = ImGui::GetIO();
|
||||
|
||||
g_fntNewRodin = ImFontAtlasSnapshot::GetFont("FOT-NewRodinPro-M.otf");
|
||||
g_fntNewRodinLQ = ImFontAtlasSnapshot::GetFont("FOT-NewRodinPro-M.otf");
|
||||
|
||||
g_upControllerIcons = LOAD_ZSTD_TEXTURE(g_controller);
|
||||
g_upKBMIcons = LOAD_ZSTD_TEXTURE(g_kbm);
|
||||
}
|
||||
@@ -241,10 +233,9 @@ void ButtonGuide::Draw()
|
||||
ImVec2 regionMin = { g_aspectRatioOffsetX + Scale(g_sideMargins), g_aspectRatioOffsetY * 2.0f + Scale(720.0f - 102.0f) };
|
||||
ImVec2 regionMax = { g_aspectRatioOffsetX + Scale(1280.0f - g_sideMargins), g_aspectRatioOffsetY * 2.0f + Scale(720.0f) };
|
||||
|
||||
auto textMarginX = Scale(57);
|
||||
auto textMarginY = Scale(8);
|
||||
auto textMarginX = Scale(21.25f);
|
||||
auto iconMarginX = Scale(4);
|
||||
auto fontSize = Scale(22.5f);
|
||||
auto fontSize = Scale(21.8f);
|
||||
|
||||
auto offsetLeft = 0.0f;
|
||||
auto offsetRight = 0.0f;
|
||||
@@ -260,18 +251,20 @@ void ButtonGuide::Draw()
|
||||
if (btn.Visibility && !*btn.Visibility)
|
||||
continue;
|
||||
|
||||
auto str = Localise(btn.Name.c_str()).c_str();
|
||||
auto str = Localise(btn.Name).c_str();
|
||||
auto iconWidth = Scale(g_iconWidths[btn.Icon]);
|
||||
auto iconHeight = Scale(g_iconHeights[btn.Icon]);
|
||||
auto textSize = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str);
|
||||
auto textWidth = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str).x;
|
||||
auto maxWidth = btn.MaxWidth == FLT_MAX ? textWidth : Scale(btn.MaxWidth);
|
||||
auto textScale = std::min(1.0f, maxWidth / textWidth);
|
||||
|
||||
if (i > 0)
|
||||
offsetLeft += textSize.x + iconWidth + textMarginX;
|
||||
offsetLeft += maxWidth + iconWidth + textMarginX;
|
||||
|
||||
ImVec2 iconMin = { regionMin.x + offsetLeft - iconWidth - iconMarginX, regionMin.y };
|
||||
ImVec2 iconMax = { regionMin.x + offsetLeft - iconMarginX, regionMin.y + iconHeight };
|
||||
|
||||
DrawGuide(&offsetLeft, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textSize, fontSize, str);
|
||||
DrawGuide(&offsetLeft, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textWidth, maxWidth, textScale, fontSize, str);
|
||||
}
|
||||
|
||||
// Draw right aligned icons.
|
||||
@@ -285,18 +278,20 @@ void ButtonGuide::Draw()
|
||||
if (btn.Visibility && !*btn.Visibility)
|
||||
continue;
|
||||
|
||||
auto str = Localise(btn.Name.c_str()).c_str();
|
||||
auto str = Localise(btn.Name).c_str();
|
||||
auto iconWidth = Scale(g_iconWidths[btn.Icon]);
|
||||
auto iconHeight = Scale(g_iconHeights[btn.Icon]);
|
||||
auto textSize = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str);
|
||||
auto textWidth = g_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, str).x;
|
||||
auto maxWidth = btn.MaxWidth == FLT_MAX ? textWidth : Scale(btn.MaxWidth);
|
||||
auto textScale = std::min(1.0f, maxWidth / textWidth);
|
||||
|
||||
if (i < g_buttons.size() - 1)
|
||||
offsetRight += textSize.x + iconWidth + textMarginX;
|
||||
offsetRight += maxWidth + iconWidth + textMarginX;
|
||||
|
||||
ImVec2 iconMin = { regionMax.x - offsetRight - iconWidth - iconMarginX, regionMin.y };
|
||||
ImVec2 iconMax = { regionMax.x - offsetRight - iconMarginX, regionMin.y + iconHeight };
|
||||
|
||||
DrawGuide(&offsetRight, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textSize, fontSize, str);
|
||||
DrawGuide(&offsetRight, regionMin, regionMax, btn.Icon, btn.Alignment, iconMin, iconMax, btn.FontQuality, textWidth, maxWidth, textScale, fontSize, str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,19 +40,23 @@ class Button
|
||||
{
|
||||
public:
|
||||
std::string Name{};
|
||||
float MaxWidth{ FLT_MAX };
|
||||
EButtonIcon Icon{};
|
||||
EButtonAlignment Alignment{ EButtonAlignment::Right };
|
||||
EFontQuality FontQuality{ EFontQuality::High };
|
||||
bool* Visibility{ nullptr };
|
||||
|
||||
Button(std::string name, EButtonIcon icon, EButtonAlignment alignment, EFontQuality fontQuality = EFontQuality::High, bool* visibility = nullptr)
|
||||
: Name(name), Icon(icon), Alignment(alignment), FontQuality(fontQuality), Visibility(visibility) {}
|
||||
Button(std::string name, float maxWidth, EButtonIcon icon, EButtonAlignment alignment, EFontQuality fontQuality = EFontQuality::High, bool* visibility = nullptr)
|
||||
: Name(name), MaxWidth(maxWidth), Icon(icon), Alignment(alignment), FontQuality(fontQuality), Visibility(visibility) {}
|
||||
|
||||
Button(std::string name, EButtonIcon icon, EButtonAlignment alignment, bool* visibility) : Name(name), Icon(icon), Alignment(alignment), Visibility(visibility) {}
|
||||
Button(std::string name, float maxWidth, EButtonIcon icon, EButtonAlignment alignment, bool* visibility)
|
||||
: Name(name), MaxWidth(maxWidth), Icon(icon), Alignment(alignment), Visibility(visibility) {}
|
||||
|
||||
Button(std::string name, EButtonIcon icon, bool* visibility) : Name(name), Icon(icon), Visibility(visibility) {}
|
||||
Button(std::string name, float maxWidth, EButtonIcon icon, bool* visibility)
|
||||
: Name(name), MaxWidth(maxWidth), Icon(icon), Visibility(visibility) {}
|
||||
|
||||
Button(std::string name, EButtonIcon icon) : Name(name), Icon(icon) {}
|
||||
Button(std::string name, float maxWidth, EButtonIcon icon, EFontQuality fontQuality = EFontQuality::High)
|
||||
: Name(name), MaxWidth(maxWidth), Icon(icon), FontQuality(fontQuality) {}
|
||||
};
|
||||
|
||||
class ButtonGuide
|
||||
|
||||
@@ -45,6 +45,9 @@ void ResetGradient()
|
||||
|
||||
void SetShaderModifier(uint32_t shaderModifier)
|
||||
{
|
||||
if (shaderModifier == IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT && Config::DisableLowResolutionFontOnCustomUI)
|
||||
shaderModifier = IMGUI_SHADER_MODIFIER_NONE;
|
||||
|
||||
auto callbackData = AddImGuiCallback(ImGuiCallback::SetShaderModifier);
|
||||
callbackData->setShaderModifier.shaderModifier = shaderModifier;
|
||||
}
|
||||
@@ -461,17 +464,39 @@ std::vector<std::string> Split(const char* strStart, const ImFont* font, float f
|
||||
const bool wordWrapEnabled = (maxWidth > 0.0f);
|
||||
const char *wordWrapEOL = nullptr;
|
||||
|
||||
auto IsKanji = [](const char* str, const char* strEnd)
|
||||
{
|
||||
const char* tempStr = str;
|
||||
unsigned int c = (unsigned int)*tempStr;
|
||||
if (c < 0x80)
|
||||
tempStr += 1;
|
||||
else
|
||||
tempStr += ImTextCharFromUtf8(&c, tempStr, strEnd);
|
||||
|
||||
// Basic CJK and CJK Extension A
|
||||
return (c >= 0x4E00 && c <= 0x9FBF) || (c >= 0x3400 && c <= 0x4DBF);
|
||||
};
|
||||
|
||||
while (*str != 0)
|
||||
{
|
||||
if (wordWrapEnabled)
|
||||
{
|
||||
if (wordWrapEOL == nullptr)
|
||||
{
|
||||
wordWrapEOL = font->CalcWordWrapPositionA(scale, str, strEnd, maxWidth - lineWidth);
|
||||
wordWrapEOL = CalcWordWrapPositionA(font, scale, str, strEnd, maxWidth - lineWidth);
|
||||
}
|
||||
|
||||
if (str >= wordWrapEOL)
|
||||
{
|
||||
if (IsKanji(str, strEnd))
|
||||
{
|
||||
// If the current character is Kanji, move back to prevent splitting Kanji
|
||||
while (str > lineStart && IsKanji(str - 3, strEnd))
|
||||
{
|
||||
str -= 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (textWidth < lineWidth)
|
||||
textWidth = lineWidth;
|
||||
|
||||
@@ -645,7 +670,7 @@ ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidt
|
||||
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, bool leadingSpace)
|
||||
{
|
||||
auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER;
|
||||
|
||||
@@ -653,8 +678,14 @@ void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, c
|
||||
auto lines = Split(input.first.c_str(), font, fontSize, maxWidth);
|
||||
|
||||
for (auto& line : lines)
|
||||
{
|
||||
line = ReAddRubyAnnotations(line, input.second);
|
||||
|
||||
if (!line.empty() && line.substr(0, 3) != "「" && leadingSpace)
|
||||
{
|
||||
line.insert(0, " ");
|
||||
}
|
||||
}
|
||||
|
||||
auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines);
|
||||
auto offsetY = 0.0f;
|
||||
|
||||
@@ -823,3 +854,105 @@ void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha)
|
||||
drawList->AddImage(g_texLight.get(), min, max, GET_UV_COORDS(lightOffUVs), lightCol);
|
||||
}
|
||||
}
|
||||
|
||||
// Taken from ImGui because we need to modify to break for '\u200B\ too
|
||||
// Simple word-wrapping for English, not full-featured. Please submit failing cases!
|
||||
// This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end.
|
||||
// FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.)
|
||||
const char* CalcWordWrapPositionA(const ImFont* font, float scale, const char* text, const char* text_end, float wrap_width)
|
||||
{
|
||||
// For references, possible wrap point marked with ^
|
||||
// "aaa bbb, ccc,ddd. eee fff. ggg!"
|
||||
// ^ ^ ^ ^ ^__ ^ ^
|
||||
|
||||
// List of hardcoded separators: .,;!?'"
|
||||
|
||||
// Skip extra blanks after a line returns (that includes not counting them in width computation)
|
||||
// e.g. "Hello world" --> "Hello" "World"
|
||||
|
||||
// Cut words that cannot possibly fit within one line.
|
||||
// e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
|
||||
float line_width = 0.0f;
|
||||
float word_width = 0.0f;
|
||||
float blank_width = 0.0f;
|
||||
wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
|
||||
|
||||
const char* word_end = text;
|
||||
const char* prev_word_end = NULL;
|
||||
bool inside_word = true;
|
||||
|
||||
const char* s = text;
|
||||
IM_ASSERT(text_end != NULL);
|
||||
while (s < text_end)
|
||||
{
|
||||
unsigned int c = (unsigned int)*s;
|
||||
const char* next_s;
|
||||
if (c < 0x80)
|
||||
next_s = s + 1;
|
||||
else
|
||||
next_s = s + ImTextCharFromUtf8(&c, s, text_end);
|
||||
|
||||
if (c < 32)
|
||||
{
|
||||
if (c == '\n')
|
||||
{
|
||||
line_width = word_width = blank_width = 0.0f;
|
||||
inside_word = true;
|
||||
s = next_s;
|
||||
continue;
|
||||
}
|
||||
if (c == '\r')
|
||||
{
|
||||
s = next_s;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const float char_width = ((int)c < font->IndexAdvanceX.Size ? font->IndexAdvanceX.Data[c] : font->FallbackAdvanceX);
|
||||
if (ImCharIsBlankW(c) || c == 0x200B)
|
||||
{
|
||||
if (inside_word)
|
||||
{
|
||||
line_width += blank_width;
|
||||
blank_width = 0.0f;
|
||||
word_end = s;
|
||||
}
|
||||
blank_width += char_width;
|
||||
inside_word = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
word_width += char_width;
|
||||
if (inside_word)
|
||||
{
|
||||
word_end = next_s;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_word_end = word_end;
|
||||
line_width += word_width + blank_width;
|
||||
word_width = blank_width = 0.0f;
|
||||
}
|
||||
|
||||
// Allow wrapping after punctuation.
|
||||
inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"');
|
||||
}
|
||||
|
||||
// We ignore blank width at the end of the line (they can be skipped)
|
||||
if (line_width + word_width > wrap_width)
|
||||
{
|
||||
// Words that cannot possibly fit within an entire line will be cut anywhere.
|
||||
if (word_width < wrap_width)
|
||||
s = prev_word_end ? prev_word_end : word_end;
|
||||
break;
|
||||
}
|
||||
|
||||
s = next_s;
|
||||
}
|
||||
|
||||
// Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
|
||||
// +1 may not be a character start point in UTF-8 but it's ok because caller loops use (text >= word_wrap_eol).
|
||||
if (s == text && text < text_end)
|
||||
return s + 1;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ std::vector<std::string> RemoveAnnotationFromParagraph(const std::vector<std::st
|
||||
std::string RemoveAnnotationFromParagraphLine(const std::vector<TextSegment>& annotatedLine);
|
||||
ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, const std::vector<std::string>& lines);
|
||||
ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidth, float lineMargin, const char* text);
|
||||
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 = false);
|
||||
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 = false, bool leadingSpace = false);
|
||||
float Lerp(float a, float b, float t);
|
||||
float Cubic(float a, float b, float t);
|
||||
float Hermite(float a, float b, float t);
|
||||
@@ -81,3 +81,4 @@ ImU32 ColourLerp(ImU32 c0, ImU32 c1, float t);
|
||||
void DrawVersionString(const ImFont* font, const ImU32 col = IM_COL32(255, 255, 255, 70));
|
||||
void DrawSelectionContainer(ImVec2 min, ImVec2 max, bool fadeTop = false);
|
||||
void DrawToggleLight(ImVec2 pos, bool isEnabled, float alpha = 1.0f);
|
||||
const char* CalcWordWrapPositionA(const ImFont* font, float scale, const char* text, const char* text_end, float wrap_width);
|
||||
|
||||
@@ -736,6 +736,14 @@ static void DrawDescriptionContainer()
|
||||
}
|
||||
else if (g_currentPage == WizardPage::InstallFailed)
|
||||
{
|
||||
// Japanese needs text to be brought in by a normal width space
|
||||
// as it allows for text to begin further than others for
|
||||
// special characters.
|
||||
if (Config::Language == ELanguage::Japanese)
|
||||
{
|
||||
strncat(descriptionText, " ", 1);
|
||||
}
|
||||
|
||||
strncat(descriptionText, g_installerErrorMessage.c_str(), sizeof(descriptionText) - 1);
|
||||
}
|
||||
|
||||
@@ -769,6 +777,8 @@ static void DrawDescriptionContainer()
|
||||
|
||||
textX += annotationFontSize;
|
||||
textY += annotationFontSize;
|
||||
|
||||
lineWidth += annotationFontSize;
|
||||
}
|
||||
|
||||
drawList->PushClipRect(clipRectMin, clipRectMax, false);
|
||||
@@ -788,7 +798,9 @@ static void DrawDescriptionContainer()
|
||||
[=](const char* str, float size, ImVec2 pos)
|
||||
{
|
||||
DrawTextBasic(g_seuratFont, size, pos, IM_COL32(255, 255, 255, 255 * textAlpha), str);
|
||||
}
|
||||
},
|
||||
false,
|
||||
Config::Language == ELanguage::Japanese
|
||||
);
|
||||
|
||||
drawList->PopClipRect();
|
||||
@@ -872,7 +884,7 @@ static void DrawDescriptionContainer()
|
||||
|
||||
if (g_currentPage == WizardPage::InstallSucceeded && textAlpha >= 1.0)
|
||||
{
|
||||
ButtonGuide::Open(Button("Common_Select", selectIcon));
|
||||
ButtonGuide::Open(Button("Common_Select", 115.0f, selectIcon));
|
||||
}
|
||||
else if (g_currentPage != WizardPage::Installing && textAlpha >= 1.0)
|
||||
{
|
||||
@@ -884,15 +896,15 @@ static void DrawDescriptionContainer()
|
||||
|
||||
std::array<Button, 2> buttons =
|
||||
{
|
||||
Button("Common_Select", selectIcon),
|
||||
Button(backKey, backIcon)
|
||||
Button("Common_Select", 115.0f, selectIcon),
|
||||
Button(backKey, FLT_MAX, backIcon)
|
||||
};
|
||||
|
||||
ButtonGuide::Open(buttons);
|
||||
}
|
||||
else if (g_currentPage == WizardPage::Installing)
|
||||
{
|
||||
ButtonGuide::Open(Button("Common_Cancel", backIcon));
|
||||
ButtonGuide::Open(Button("Common_Cancel", FLT_MAX, backIcon));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1399,7 +1411,7 @@ static void DrawNavigationButton()
|
||||
|
||||
float squashRatio;
|
||||
constexpr float NAV_BUTTON_MAX_TEXT_WIDTH = 90.0f;
|
||||
const char *nextButtonKey = "Installer_Button_Next";
|
||||
std::string_view nextButtonKey = "Installer_Button_Next";
|
||||
if (skipButton)
|
||||
{
|
||||
nextButtonKey = "Installer_Button_Skip";
|
||||
|
||||
@@ -223,6 +223,10 @@ void DrawButton(int rowIndex, float yOffset, float width, float height, std::str
|
||||
auto fontSize = Scale(28);
|
||||
auto textSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, text.c_str());
|
||||
|
||||
// Show low quality text in-game.
|
||||
if (App::s_isInit)
|
||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
|
||||
|
||||
DrawTextWithShadow
|
||||
(
|
||||
g_fntSeurat,
|
||||
@@ -231,6 +235,10 @@ void DrawButton(int rowIndex, float yOffset, float width, float height, std::str
|
||||
isSelected ? IM_COL32(255, 128, 0, 255) : IM_COL32(255, 255, 255, 255),
|
||||
text.c_str()
|
||||
);
|
||||
|
||||
// Reset the shader modifier.
|
||||
if (App::s_isInit)
|
||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
|
||||
}
|
||||
|
||||
void DrawNextButtonGuide(bool isController, bool isKeyboard)
|
||||
@@ -241,11 +249,16 @@ void DrawNextButtonGuide(bool isController, bool isKeyboard)
|
||||
? EButtonIcon::Enter
|
||||
: EButtonIcon::LMB;
|
||||
|
||||
// Always show controller prompt in-game.
|
||||
if (App::s_isInit)
|
||||
icon = EButtonIcon::A;
|
||||
auto fontQuality = EFontQuality::High;
|
||||
|
||||
ButtonGuide::Open(Button("Common_Next", icon));
|
||||
// Always show controller prompt and low quality text in-game.
|
||||
if (App::s_isInit)
|
||||
{
|
||||
icon = EButtonIcon::A;
|
||||
fontQuality = EFontQuality::Low;
|
||||
}
|
||||
|
||||
ButtonGuide::Open(Button("Common_Next", FLT_MAX, icon, fontQuality));
|
||||
}
|
||||
|
||||
static void ResetSelection()
|
||||
@@ -338,6 +351,10 @@ void MessageWindow::Draw()
|
||||
|
||||
if (DrawContainer(g_appearTime, centre, { textSize.x / 2 + textMarginX, textSize.y / 2 + textMarginY }, !g_isControlsVisible))
|
||||
{
|
||||
// Use low quality text when the game is booted to not clash with existing UI.
|
||||
if (App::s_isInit)
|
||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
|
||||
|
||||
DrawRubyAnnotatedText
|
||||
(
|
||||
g_fntSeurat,
|
||||
@@ -353,12 +370,16 @@ void MessageWindow::Draw()
|
||||
},
|
||||
[=](const char* str, float size, ImVec2 pos)
|
||||
{
|
||||
DrawTextWithShadow(g_fntSeurat, size, pos, IM_COL32(255, 255, 255, 255), str, 1.0f);
|
||||
DrawTextWithShadow(g_fntSeurat, size, pos, IM_COL32(255, 255, 255, 255), str, 1.5f, 1.5f);
|
||||
},
|
||||
|
||||
true
|
||||
);
|
||||
|
||||
// Reset the shader modifier.
|
||||
if (App::s_isInit)
|
||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT);
|
||||
|
||||
drawList->PopClipRect();
|
||||
|
||||
if (g_buttons.size())
|
||||
@@ -423,10 +444,17 @@ void MessageWindow::Draw()
|
||||
backIcon = EButtonIcon::Escape;
|
||||
}
|
||||
|
||||
auto fontQuality = EFontQuality::High;
|
||||
if (App::s_isInit)
|
||||
{
|
||||
// Show low quality text in-game.
|
||||
fontQuality = EFontQuality::Low;
|
||||
}
|
||||
|
||||
std::array<Button, 2> buttons =
|
||||
{
|
||||
Button("Common_Select", selectIcon),
|
||||
Button("Common_Back", backIcon),
|
||||
Button("Common_Select", 115.0f, selectIcon, fontQuality),
|
||||
Button("Common_Back", FLT_MAX, backIcon, fontQuality),
|
||||
};
|
||||
|
||||
ButtonGuide::Open(buttons);
|
||||
@@ -470,8 +498,8 @@ void MessageWindow::Draw()
|
||||
|
||||
std::array<Button, 2> buttons =
|
||||
{
|
||||
Button(Localise("Common_Select"), EButtonIcon::LMB),
|
||||
Button(Localise("Common_Back"), EButtonIcon::Escape),
|
||||
Button("Common_Select", 115.0f, EButtonIcon::LMB),
|
||||
Button("Common_Back", FLT_MAX, EButtonIcon::Escape),
|
||||
};
|
||||
|
||||
ButtonGuide::Open(buttons);
|
||||
|
||||
@@ -449,11 +449,8 @@ static bool DrawCategories()
|
||||
|
||||
auto inputState = SWA::CInputState::GetInstance();
|
||||
|
||||
bool moveLeft = !g_lockedOnOption && (inputState->GetPadState().IsTapped(SWA::eKeyState_LeftBumper) ||
|
||||
inputState->GetPadState().IsTapped(SWA::eKeyState_LeftTrigger));
|
||||
|
||||
bool moveRight = !g_lockedOnOption && (inputState->GetPadState().IsTapped(SWA::eKeyState_RightBumper) ||
|
||||
inputState->GetPadState().IsTapped(SWA::eKeyState_RightTrigger));
|
||||
bool moveLeft = !g_lockedOnOption && inputState->GetPadState().IsTapped(SWA::eKeyState_LeftBumper);
|
||||
bool moveRight = !g_lockedOnOption && inputState->GetPadState().IsTapped(SWA::eKeyState_RightBumper);
|
||||
|
||||
if (moveLeft)
|
||||
{
|
||||
@@ -1497,6 +1494,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
||||
|
||||
auto textX = clipRectMin.x - Scale(0.5f);
|
||||
auto textY = thumbnailMax.y + offsetY;
|
||||
float lineWidth = clipRectMax.x - clipRectMin.x;
|
||||
|
||||
if (Config::Language == ELanguage::Japanese)
|
||||
{
|
||||
@@ -1511,9 +1509,13 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
||||
clipRectMax.x += annotationFontSize;
|
||||
|
||||
textY += annotationFontSize;
|
||||
|
||||
// Dirty hack to disallow clipping on Japanese text
|
||||
// whilst allowing annotations to go over the border
|
||||
lineWidth -= annotationFontSize;
|
||||
}
|
||||
|
||||
auto textSize = MeasureCentredParagraph(g_seuratFont, fontSize, clipRectMax.x - clipRectMin.x, 5.0f, desc.c_str());
|
||||
auto textSize = MeasureCentredParagraph(g_seuratFont, fontSize, lineWidth, 5.0f, desc.c_str());
|
||||
|
||||
drawList->PushClipRect(clipRectMin, clipRectMax, false);
|
||||
|
||||
@@ -1589,7 +1591,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax)
|
||||
(
|
||||
g_seuratFont,
|
||||
fontSize,
|
||||
clipRectMax.x - clipRectMin.x,
|
||||
lineWidth,
|
||||
{ textX, textY - scrollOffset },
|
||||
5.0f,
|
||||
desc.c_str(),
|
||||
@@ -1790,10 +1792,10 @@ void OptionsMenu::Open(bool isPause, SWA::EMenuType pauseMenuType)
|
||||
|
||||
std::array<Button, 4> buttons =
|
||||
{
|
||||
Button("Common_Switch", EButtonIcon::LBRB, EButtonAlignment::Left, &g_isControlsVisible),
|
||||
Button("Common_Reset", EButtonIcon::X, &g_canReset),
|
||||
Button("Common_Select", EButtonIcon::A, &g_isControlsVisible),
|
||||
Button("Common_Back", EButtonIcon::B, &g_isControlsVisible)
|
||||
Button("Common_Switch", 115.0f, EButtonIcon::LBRB, EButtonAlignment::Left, &g_isControlsVisible),
|
||||
Button("Common_Reset", 110.0f, EButtonIcon::X, &g_canReset),
|
||||
Button("Common_Select", 115.0f, EButtonIcon::A, &g_isControlsVisible),
|
||||
Button("Common_Back", 65.0f, EButtonIcon::B, &g_isControlsVisible)
|
||||
};
|
||||
|
||||
ButtonGuide::Open(buttons);
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
#include <decompressor.h>
|
||||
#include <hid/hid.h>
|
||||
|
||||
// TODO (Hyper): lower the resolution of these textures once final.
|
||||
#include <res/images/options_menu/thumbnails/achievement_notifications.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/allow_background_input.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/allow_background_input_xb.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/allow_background_input_ps.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/antialiasing_none.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/antialiasing_2x.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/antialiasing_4x.dds.h>
|
||||
@@ -14,8 +14,8 @@
|
||||
#include <res/images/options_menu/thumbnails/brightness.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/channel_stereo.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/channel_surround.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/control_tutorial_xb.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/control_tutorial_ps.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/control_tutorial_xb.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/controller_icons.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/default.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/effects_volume.dds.h>
|
||||
@@ -35,23 +35,21 @@
|
||||
#include <res/images/options_menu/thumbnails/movie_scale_fill.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/music_attenuation.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/music_volume.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/resolution_scale.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/shadow_resolution_original.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/shadow_resolution_x512.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/shadow_resolution_x1024.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/shadow_resolution_x2048.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/shadow_resolution_x4096.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/shadow_resolution_x8192.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/subtitles.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/time_transition_xb.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/time_transition_ps.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/time_transition_xb.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/transparency_antialiasing_false.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/transparency_antialiasing_true.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/ui_alignment_centre.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/ui_alignment_edge.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/vertical_camera.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/voice_language.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/vibration.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/vibration_ps.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/vibration_xb.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/vsync_on.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/vsync_off.dds.h>
|
||||
#include <res/images/options_menu/thumbnails/window_size.dds.h>
|
||||
@@ -59,7 +57,15 @@
|
||||
|
||||
#define VALUE_THUMBNAIL_MAP(type) std::unordered_map<type, std::unique_ptr<GuestTexture>>
|
||||
|
||||
static std::unordered_map<std::string_view, std::unique_ptr<GuestTexture>> g_namedThumbnails;
|
||||
static std::unique_ptr<GuestTexture> g_defaultThumbnail;
|
||||
|
||||
static std::unique_ptr<GuestTexture> g_controlTutorialXBThumbnail;
|
||||
static std::unique_ptr<GuestTexture> g_controlTutorialPSThumbnail;
|
||||
static std::unique_ptr<GuestTexture> g_vibrationXBThumbnail;
|
||||
static std::unique_ptr<GuestTexture> g_vibrationPSThumbnail;
|
||||
static std::unique_ptr<GuestTexture> g_backgroundInputXBThumbnail;
|
||||
static std::unique_ptr<GuestTexture> g_backgroundInputPSThumbnail;
|
||||
|
||||
static std::unordered_map<const IConfigDef*, std::unique_ptr<GuestTexture>> g_configThumbnails;
|
||||
|
||||
static VALUE_THUMBNAIL_MAP(ETimeOfDayTransition) g_timeOfDayTransitionThumbnails;
|
||||
@@ -76,14 +82,17 @@ static VALUE_THUMBNAIL_MAP(EUIAlignmentMode) g_uiAlignmentThumbnails;
|
||||
|
||||
void LoadThumbnails()
|
||||
{
|
||||
g_namedThumbnails["Default"] = LOAD_ZSTD_TEXTURE(g_default);
|
||||
g_namedThumbnails["WindowSize"] = LOAD_ZSTD_TEXTURE(g_window_size);
|
||||
g_namedThumbnails["ControlTutorialXB"] = LOAD_ZSTD_TEXTURE(g_control_tutorial_xb);
|
||||
g_namedThumbnails["ControlTutorialPS"] = LOAD_ZSTD_TEXTURE(g_control_tutorial_ps);
|
||||
g_defaultThumbnail = LOAD_ZSTD_TEXTURE(g_default);
|
||||
|
||||
g_controlTutorialXBThumbnail = LOAD_ZSTD_TEXTURE(g_control_tutorial_xb);
|
||||
g_controlTutorialPSThumbnail = LOAD_ZSTD_TEXTURE(g_control_tutorial_ps);
|
||||
g_vibrationXBThumbnail = LOAD_ZSTD_TEXTURE(g_vibration_xb);
|
||||
g_vibrationPSThumbnail = LOAD_ZSTD_TEXTURE(g_vibration_ps);
|
||||
g_backgroundInputXBThumbnail = LOAD_ZSTD_TEXTURE(g_allow_background_input_xb);
|
||||
g_backgroundInputPSThumbnail = LOAD_ZSTD_TEXTURE(g_allow_background_input_ps);
|
||||
|
||||
g_configThumbnails[&Config::Language] = LOAD_ZSTD_TEXTURE(g_language);
|
||||
g_configThumbnails[&Config::VoiceLanguage] = LOAD_ZSTD_TEXTURE(g_voice_language);
|
||||
g_configThumbnails[&Config::Subtitles] = LOAD_ZSTD_TEXTURE(g_subtitles);
|
||||
g_configThumbnails[&Config::Hints] = LOAD_ZSTD_TEXTURE(g_hints);
|
||||
g_configThumbnails[&Config::AchievementNotifications] = LOAD_ZSTD_TEXTURE(g_achievement_notifications);
|
||||
|
||||
@@ -92,8 +101,6 @@ void LoadThumbnails()
|
||||
|
||||
g_configThumbnails[&Config::HorizontalCamera] = LOAD_ZSTD_TEXTURE(g_horizontal_camera);
|
||||
g_configThumbnails[&Config::VerticalCamera] = LOAD_ZSTD_TEXTURE(g_vertical_camera);
|
||||
g_configThumbnails[&Config::Vibration] = LOAD_ZSTD_TEXTURE(g_vibration);
|
||||
g_configThumbnails[&Config::AllowBackgroundInput] = LOAD_ZSTD_TEXTURE(g_allow_background_input);
|
||||
g_configThumbnails[&Config::ControllerIcons] = LOAD_ZSTD_TEXTURE(g_controller_icons);
|
||||
g_configThumbnails[&Config::MasterVolume] = LOAD_ZSTD_TEXTURE(g_master_volume);
|
||||
g_configThumbnails[&Config::MusicVolume] = LOAD_ZSTD_TEXTURE(g_music_volume);
|
||||
@@ -107,8 +114,8 @@ void LoadThumbnails()
|
||||
g_configThumbnails[&Config::WindowSize] = LOAD_ZSTD_TEXTURE(g_window_size);
|
||||
g_configThumbnails[&Config::Monitor] = LOAD_ZSTD_TEXTURE(g_monitor);
|
||||
g_configThumbnails[&Config::AspectRatio] = LOAD_ZSTD_TEXTURE(g_aspect_ratio);
|
||||
g_configThumbnails[&Config::ResolutionScale] = LOAD_ZSTD_TEXTURE(g_resolution_scale);
|
||||
g_configThumbnails[&Config::Fullscreen] = LOAD_ZSTD_TEXTURE(g_fullscreen);
|
||||
g_configThumbnails[&Config::XboxColorCorrection] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction);
|
||||
|
||||
g_vsyncThumbnails[false] = LOAD_ZSTD_TEXTURE(g_vsync_off);
|
||||
g_vsyncThumbnails[true] = LOAD_ZSTD_TEXTURE(g_vsync_on);
|
||||
@@ -124,7 +131,6 @@ void LoadThumbnails()
|
||||
g_transparencyAntiAliasingThumbnails[false] = LOAD_ZSTD_TEXTURE(g_transparency_antialiasing_false);
|
||||
g_transparencyAntiAliasingThumbnails[true] = LOAD_ZSTD_TEXTURE(g_transparency_antialiasing_true);
|
||||
|
||||
g_shadowResolutionThumbnails[EShadowResolution::Original] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_original);
|
||||
g_shadowResolutionThumbnails[EShadowResolution::x512] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_x512);
|
||||
g_shadowResolutionThumbnails[EShadowResolution::x1024] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_x1024);
|
||||
g_shadowResolutionThumbnails[EShadowResolution::x2048] = LOAD_ZSTD_TEXTURE(g_shadow_resolution_x2048);
|
||||
@@ -143,8 +149,6 @@ void LoadThumbnails()
|
||||
|
||||
g_uiAlignmentThumbnails[EUIAlignmentMode::Centre] = LOAD_ZSTD_TEXTURE(g_ui_alignment_centre);
|
||||
g_uiAlignmentThumbnails[EUIAlignmentMode::Edge] = LOAD_ZSTD_TEXTURE(g_ui_alignment_edge);
|
||||
|
||||
g_configThumbnails[&Config::XboxColorCorrection] = LOAD_ZSTD_TEXTURE(g_xbox_color_correction);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -156,40 +160,50 @@ bool TryGetValueThumbnail(const IConfigDef* cfg, VALUE_THUMBNAIL_MAP(T)* thumbna
|
||||
if (!cfg->GetValue())
|
||||
return false;
|
||||
|
||||
auto result = thumbnails->at(*(T*)cfg->GetValue()).get();
|
||||
T value = *(T*)cfg->GetValue();
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
if constexpr (std::is_same_v<T, EShadowResolution>)
|
||||
{
|
||||
if (value == EShadowResolution::Original)
|
||||
value = EShadowResolution::x1024;
|
||||
}
|
||||
|
||||
*texture = result;
|
||||
auto findResult = thumbnails->find(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
if (findResult != thumbnails->end())
|
||||
{
|
||||
*texture = findResult->second.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
GuestTexture* GetThumbnail(const std::string_view name)
|
||||
{
|
||||
if (!g_namedThumbnails.count(name))
|
||||
return g_namedThumbnails["Default"].get();
|
||||
|
||||
return g_namedThumbnails[name].get();
|
||||
return false;
|
||||
}
|
||||
|
||||
GuestTexture* GetThumbnail(const IConfigDef* cfg)
|
||||
{
|
||||
if (!g_configThumbnails.count(cfg))
|
||||
auto findResult = g_configThumbnails.find(cfg);
|
||||
if (findResult == g_configThumbnails.end())
|
||||
{
|
||||
auto texture = g_namedThumbnails["Default"].get();
|
||||
auto texture = g_defaultThumbnail.get();
|
||||
|
||||
bool isPlayStation = Config::ControllerIcons == EControllerIcons::PlayStation;
|
||||
|
||||
if (Config::ControllerIcons == EControllerIcons::Auto)
|
||||
isPlayStation = hid::g_inputDeviceController == hid::EInputDevice::PlayStation;
|
||||
|
||||
if (cfg == &Config::ControlTutorial)
|
||||
{
|
||||
bool isPlayStation = Config::ControllerIcons == EControllerIcons::PlayStation;
|
||||
|
||||
if (Config::ControllerIcons == EControllerIcons::Auto)
|
||||
isPlayStation = hid::g_inputDeviceController == hid::EInputDevice::PlayStation;
|
||||
|
||||
texture = isPlayStation ? g_namedThumbnails["ControlTutorialPS"].get() : g_namedThumbnails["ControlTutorialXB"].get();
|
||||
texture = isPlayStation ? g_controlTutorialPSThumbnail.get() : g_controlTutorialXBThumbnail.get();
|
||||
}
|
||||
if (cfg == &Config::TimeOfDayTransition)
|
||||
else if (cfg == &Config::Vibration)
|
||||
{
|
||||
texture = isPlayStation ? g_vibrationPSThumbnail.get() : g_vibrationXBThumbnail.get();
|
||||
}
|
||||
else if (cfg == &Config::AllowBackgroundInput)
|
||||
{
|
||||
texture = isPlayStation ? g_backgroundInputPSThumbnail.get() : g_backgroundInputXBThumbnail.get();
|
||||
}
|
||||
else if (cfg == &Config::TimeOfDayTransition)
|
||||
{
|
||||
TryGetValueThumbnail<ETimeOfDayTransition>(cfg, &g_timeOfDayTransitionThumbnails, &texture);
|
||||
}
|
||||
@@ -237,5 +251,5 @@ GuestTexture* GetThumbnail(const IConfigDef* cfg)
|
||||
return texture;
|
||||
}
|
||||
|
||||
return g_configThumbnails[cfg].get();
|
||||
return findResult->second.get();
|
||||
}
|
||||
|
||||
@@ -5,5 +5,4 @@
|
||||
|
||||
void LoadThumbnails();
|
||||
|
||||
GuestTexture* GetThumbnail(const std::string_view name);
|
||||
GuestTexture* GetThumbnail(const IConfigDef* cfg);
|
||||
|
||||
@@ -511,43 +511,33 @@ std::string_view ConfigDef<T, isHidden>::GetName() const
|
||||
template<typename T, bool isHidden>
|
||||
std::string ConfigDef<T, isHidden>::GetNameLocalised(ELanguage language) const
|
||||
{
|
||||
if (!Locale)
|
||||
return Name;
|
||||
|
||||
if (!Locale->count(language))
|
||||
if (Locale != nullptr)
|
||||
{
|
||||
if (Locale->count(ELanguage::English))
|
||||
{
|
||||
return std::get<0>(Locale->at(ELanguage::English));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
auto languageFindResult = Locale->find(language);
|
||||
if (languageFindResult == Locale->end())
|
||||
languageFindResult = Locale->find(ELanguage::English);
|
||||
|
||||
if (languageFindResult != Locale->end())
|
||||
return std::get<0>(languageFindResult->second);
|
||||
}
|
||||
|
||||
return std::get<0>(Locale->at(language));
|
||||
return Name;
|
||||
}
|
||||
|
||||
template<typename T, bool isHidden>
|
||||
std::string ConfigDef<T, isHidden>::GetDescription(ELanguage language) const
|
||||
{
|
||||
if (!Locale)
|
||||
return "";
|
||||
|
||||
if (!Locale->count(language))
|
||||
if (Locale != nullptr)
|
||||
{
|
||||
if (Locale->count(ELanguage::English))
|
||||
{
|
||||
return std::get<1>(Locale->at(ELanguage::English));
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
auto languageFindResult = Locale->find(language);
|
||||
if (languageFindResult == Locale->end())
|
||||
languageFindResult = Locale->find(ELanguage::English);
|
||||
|
||||
if (languageFindResult != Locale->end())
|
||||
return std::get<1>(languageFindResult->second);
|
||||
}
|
||||
|
||||
return std::get<1>(Locale->at(language));
|
||||
return "";
|
||||
}
|
||||
|
||||
template<typename T, bool isHidden>
|
||||
@@ -578,27 +568,27 @@ std::string ConfigDef<T, isHidden>::GetValueLocalised(ELanguage language) const
|
||||
: Localise("Common_Off");
|
||||
}
|
||||
|
||||
if (!locale)
|
||||
return ToString(false);
|
||||
|
||||
if (!locale->count(language))
|
||||
if (locale != nullptr)
|
||||
{
|
||||
if (locale->count(ELanguage::English))
|
||||
ELanguage languages[] = { language, ELanguage::English };
|
||||
|
||||
for (auto languageToFind : languages)
|
||||
{
|
||||
language = ELanguage::English;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ToString(false);
|
||||
auto languageFindResult = locale->find(languageToFind);
|
||||
|
||||
if (languageFindResult != locale->end())
|
||||
{
|
||||
auto valueFindResult = languageFindResult->second.find(Value);
|
||||
if (valueFindResult != languageFindResult->second.end())
|
||||
return std::get<0>(valueFindResult->second);
|
||||
}
|
||||
|
||||
if (languageToFind == ELanguage::English)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto strings = locale->at(language);
|
||||
|
||||
if (!strings.count(Value))
|
||||
return ToString(false);
|
||||
|
||||
return std::get<0>(strings.at(Value));
|
||||
return ToString(false);
|
||||
}
|
||||
|
||||
template<typename T, bool isHidden>
|
||||
@@ -615,27 +605,27 @@ std::string ConfigDef<T, isHidden>::GetValueDescription(ELanguage language) cons
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!locale)
|
||||
return "";
|
||||
|
||||
if (!locale->count(language))
|
||||
if (locale != nullptr)
|
||||
{
|
||||
if (locale->count(ELanguage::English))
|
||||
ELanguage languages[] = { language, ELanguage::English };
|
||||
|
||||
for (auto languageToFind : languages)
|
||||
{
|
||||
language = ELanguage::English;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
auto languageFindResult = locale->find(languageToFind);
|
||||
|
||||
if (languageFindResult != locale->end())
|
||||
{
|
||||
auto valueFindResult = languageFindResult->second.find(Value);
|
||||
if (valueFindResult != languageFindResult->second.end())
|
||||
return std::get<1>(valueFindResult->second);
|
||||
}
|
||||
|
||||
if (languageToFind == ELanguage::English)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto strings = locale->at(language);
|
||||
|
||||
if (!strings.count(Value))
|
||||
return "";
|
||||
|
||||
return std::get<1>(strings.at(Value));
|
||||
return "";
|
||||
}
|
||||
|
||||
template<typename T, bool isHidden>
|
||||
|
||||
@@ -91,5 +91,6 @@ CONFIG_DEFINE_HIDDEN("Codes", bool, SaveScoreAtCheckpoints, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, SkipIntroLogos, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, UseArrowsForTimeOfDayTransition, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, UseOfficialTitleOnTitleBar, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableLowResolutionFontOnCustomUI, false);
|
||||
|
||||
CONFIG_DEFINE("Update", time_t, LastChecked, 0);
|
||||
|
||||
@@ -28,7 +28,10 @@ endforeach()
|
||||
add_custom_command(
|
||||
OUTPUT ${UNLEASHED_RECOMP_PPC_RECOMPILED_SOURCES}
|
||||
COMMAND $<TARGET_FILE:XenonRecomp>
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/private/default.xex" "${CMAKE_CURRENT_SOURCE_DIR}/config/SWA.toml"
|
||||
DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/private/default.xex"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/private/default.xexp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/config/SWA.toml"
|
||||
)
|
||||
|
||||
set(XENOS_RECOMP_ROOT "${UNLEASHED_RECOMP_TOOLS_ROOT}/XenosRecomp/XenosRecomp")
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
[main]
|
||||
file_path = "../private/default.xex"
|
||||
patch_file_path = "../private/default.xexp"
|
||||
patched_file_path = "../private/default_patched.xex"
|
||||
out_directory_path = "../ppc"
|
||||
switch_table_file_path = "SWA_switch_tables.toml"
|
||||
|
||||
@@ -176,6 +178,12 @@ name = "DisableHintsMidAsmHook"
|
||||
address = 0x829E409C
|
||||
jump_address_on_true = 0x829E40A0
|
||||
|
||||
# Disable Chip hints for shoe upgrades
|
||||
[[midasm_hook]]
|
||||
name = "DisableHintsMidAsmHook"
|
||||
address = 0x82691CB0
|
||||
jump_address_on_true = 0x82691E24
|
||||
|
||||
# Disable navigation volumes
|
||||
[[midasm_hook]]
|
||||
name = "DisableControlTutorialMidAsmHook"
|
||||
@@ -608,13 +616,13 @@ jump_address = 0x82585480
|
||||
name = "LoadingScreenControllerMidAsmHook"
|
||||
address = 0x824DC9D4
|
||||
|
||||
# SWA::Player::CPlayerSpeedPostureInputOnPath
|
||||
# SWA::Player::CPlayerSpeedPostureInputOnPath / SWA::Player::CPlayerSpeedPostureInputForcePath / SWA::Player::CPlayerSpeedPostureInput2DStandard
|
||||
[[midasm_hook]]
|
||||
name = "PostureDPadSupportInvertYMidAsmHook"
|
||||
address = 0x8234F194
|
||||
registers = ["r31", "f13", "f0"]
|
||||
|
||||
# SWA::Player::CPlayerSpeedPostureInputOnPathLocal
|
||||
# SWA::Player::CPlayerSpeedPostureInputPathLocal
|
||||
[[midasm_hook]]
|
||||
name = "PostureDPadSupportMidAsmHook"
|
||||
address = 0x8234F610
|
||||
@@ -722,7 +730,7 @@ name = "PostureDPadSupportXMidAsmHook"
|
||||
address = 0x8266B6AC
|
||||
registers = ["r29", "f0"]
|
||||
|
||||
# SWA::Player::CSonicStateStompingLand
|
||||
# SWA::Player::CPlayerSpeedStateNormalDamageStandUp / SWA::Player::CSonicStateStartEvent / SWA::Player::CSonicStateStompingLand
|
||||
[[midasm_hook]]
|
||||
name = "PostureDPadSupportMidAsmHook"
|
||||
address = 0x8231F824
|
||||
@@ -771,6 +779,30 @@ address = 0x82454104
|
||||
registers = ["r29", "f28", "f27"]
|
||||
after_instruction = true
|
||||
|
||||
# SWA::CBossEggBeetle
|
||||
[[midasm_hook]]
|
||||
name = "PostureDPadSupportXMidAsmHook"
|
||||
address = 0x829A4FCC
|
||||
registers = ["r29", "f13"]
|
||||
|
||||
# SWA::CBossEggRayBird (horizontal)
|
||||
[[midasm_hook]]
|
||||
name = "PostureDPadSupportXMidAsmHook"
|
||||
address = 0x829BA7E0
|
||||
registers = ["r21", "f13"]
|
||||
|
||||
# SWA::CBossEggRayBird (vertical)
|
||||
[[midasm_hook]]
|
||||
name = "PostureDPadSupportYMidAsmHook"
|
||||
address = 0x829C53E8
|
||||
registers = ["r21", "f13"]
|
||||
|
||||
# SWA::CBossEggLancer
|
||||
[[midasm_hook]]
|
||||
name = "PostureDPadSupportXMidAsmHook"
|
||||
address = 0x82A55A48
|
||||
registers = ["r21", "f13"]
|
||||
|
||||
# SWA::CWorldMapCamera - disable rotation deadzone for touch
|
||||
[[midasm_hook]]
|
||||
name = "WorldMapDeadzoneMidAsmHook"
|
||||
@@ -1056,3 +1088,8 @@ registers = ["r4"]
|
||||
name = "AnimationDataMakeMidAsmHook"
|
||||
address = 0x82BB38E4
|
||||
registers = ["r31", "r29", "r28"]
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "ObjGrindDashPanelAllocMidAsmHook"
|
||||
address = 0x82614948
|
||||
registers = ["r3"]
|
||||
|
||||
+1
-1
Submodule UnleashedRecompResources updated: 5ba3baac5a...89c82c0aa8
@@ -38,6 +38,16 @@
|
||||
"path": "private/default.xex",
|
||||
"dest": "UnleashedRecompLib/private"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"path": "private/default.xexp",
|
||||
"dest": "UnleashedRecompLib/private"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"path": "private/default_patched.xex",
|
||||
"dest": "UnleashedRecompLib/private"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"path": "private/shader.ar",
|
||||
|
||||
Vendored
-223
@@ -1,223 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based
|
||||
* on the implementation in boost::uuid::details.
|
||||
*
|
||||
* SHA1 Wikipedia Page: http://en.wikipedia.org/wiki/SHA-1
|
||||
*
|
||||
* Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Taken from https://github.com/mohaps/TinySHA1
|
||||
* Modified for use by Xenia
|
||||
*/
|
||||
#ifndef _TINY_SHA1_HPP_
|
||||
#define _TINY_SHA1_HPP_
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace sha1 {
|
||||
class SHA1 {
|
||||
public:
|
||||
typedef uint32_t digest32_t[5];
|
||||
typedef uint8_t digest8_t[20];
|
||||
inline static uint32_t LeftRotate(uint32_t value, size_t count) {
|
||||
return (value << count) ^ (value >> (32 - count));
|
||||
}
|
||||
SHA1() { reset(); }
|
||||
virtual ~SHA1() {}
|
||||
SHA1(const SHA1& s) { *this = s; }
|
||||
const SHA1& operator=(const SHA1& s) {
|
||||
memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t));
|
||||
memcpy(m_block, s.m_block, 64);
|
||||
m_blockByteIndex = s.m_blockByteIndex;
|
||||
m_byteCount = s.m_byteCount;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SHA1& init(const uint32_t digest[5], const uint8_t block[64],
|
||||
uint32_t count) {
|
||||
std::memcpy(m_digest, digest, 20);
|
||||
std::memcpy(m_block, block, count % 64);
|
||||
m_byteCount = count;
|
||||
m_blockByteIndex = count % 64;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const uint32_t* getDigest() const { return m_digest; }
|
||||
const uint8_t* getBlock() const { return m_block; }
|
||||
size_t getBlockByteIndex() const { return m_blockByteIndex; }
|
||||
size_t getByteCount() const { return m_byteCount; }
|
||||
|
||||
SHA1& reset() {
|
||||
m_digest[0] = 0x67452301;
|
||||
m_digest[1] = 0xEFCDAB89;
|
||||
m_digest[2] = 0x98BADCFE;
|
||||
m_digest[3] = 0x10325476;
|
||||
m_digest[4] = 0xC3D2E1F0;
|
||||
m_blockByteIndex = 0;
|
||||
m_byteCount = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SHA1& processByte(uint8_t octet) {
|
||||
this->m_block[this->m_blockByteIndex++] = octet;
|
||||
++this->m_byteCount;
|
||||
if (m_blockByteIndex == 64) {
|
||||
this->m_blockByteIndex = 0;
|
||||
processBlock();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SHA1& processBlock(const void* const start, const void* const end) {
|
||||
const uint8_t* begin = static_cast<const uint8_t*>(start);
|
||||
const uint8_t* finish = static_cast<const uint8_t*>(end);
|
||||
while (begin != finish) {
|
||||
processByte(*begin);
|
||||
begin++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SHA1& processBytes(const void* const data, size_t len) {
|
||||
const uint8_t* block = static_cast<const uint8_t*>(data);
|
||||
processBlock(block, block + len);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const uint32_t* finalize(digest32_t digest) {
|
||||
size_t bitCount = this->m_byteCount * 8;
|
||||
processByte(0x80);
|
||||
if (this->m_blockByteIndex > 56) {
|
||||
while (m_blockByteIndex != 0) {
|
||||
processByte(0);
|
||||
}
|
||||
while (m_blockByteIndex < 56) {
|
||||
processByte(0);
|
||||
}
|
||||
} else {
|
||||
while (m_blockByteIndex < 56) {
|
||||
processByte(0);
|
||||
}
|
||||
}
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte(static_cast<unsigned char>((bitCount >> 24) & 0xFF));
|
||||
processByte(static_cast<unsigned char>((bitCount >> 16) & 0xFF));
|
||||
processByte(static_cast<unsigned char>((bitCount >> 8) & 0xFF));
|
||||
processByte(static_cast<unsigned char>((bitCount)&0xFF));
|
||||
|
||||
memcpy(digest, m_digest, 5 * sizeof(uint32_t));
|
||||
return digest;
|
||||
}
|
||||
|
||||
const uint8_t* finalize(digest8_t digest) {
|
||||
digest32_t d32;
|
||||
finalize(d32);
|
||||
size_t di = 0;
|
||||
digest[di++] = ((d32[0] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[0] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[0] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[0]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[1] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[1] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[1] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[1]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[2] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[2] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[2] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[2]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[3] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[3] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[3] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[3]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[4] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[4] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[4] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[4]) & 0xFF);
|
||||
return digest;
|
||||
}
|
||||
|
||||
protected:
|
||||
void processBlock() {
|
||||
uint32_t w[80];
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
w[i] = (m_block[i * 4 + 0] << 24);
|
||||
w[i] |= (m_block[i * 4 + 1] << 16);
|
||||
w[i] |= (m_block[i * 4 + 2] << 8);
|
||||
w[i] |= (m_block[i * 4 + 3]);
|
||||
}
|
||||
for (size_t i = 16; i < 80; i++) {
|
||||
w[i] = LeftRotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
|
||||
}
|
||||
|
||||
uint32_t a = m_digest[0];
|
||||
uint32_t b = m_digest[1];
|
||||
uint32_t c = m_digest[2];
|
||||
uint32_t d = m_digest[3];
|
||||
uint32_t e = m_digest[4];
|
||||
|
||||
for (std::size_t i = 0; i < 80; ++i) {
|
||||
uint32_t f = 0;
|
||||
uint32_t k = 0;
|
||||
|
||||
if (i < 20) {
|
||||
f = (b & c) | (~b & d);
|
||||
k = 0x5A827999;
|
||||
} else if (i < 40) {
|
||||
f = b ^ c ^ d;
|
||||
k = 0x6ED9EBA1;
|
||||
} else if (i < 60) {
|
||||
f = (b & c) | (b & d) | (c & d);
|
||||
k = 0x8F1BBCDC;
|
||||
} else {
|
||||
f = b ^ c ^ d;
|
||||
k = 0xCA62C1D6;
|
||||
}
|
||||
uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = LeftRotate(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
m_digest[0] += a;
|
||||
m_digest[1] += b;
|
||||
m_digest[2] += c;
|
||||
m_digest[3] += d;
|
||||
m_digest[4] += e;
|
||||
}
|
||||
|
||||
private:
|
||||
digest32_t m_digest;
|
||||
uint8_t m_block[64];
|
||||
size_t m_blockByteIndex;
|
||||
size_t m_byteCount;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
Vendored
-1
Submodule thirdparty/libmspack deleted from 305907723a
Vendored
-1
Submodule thirdparty/tiny-AES-c deleted from 23856752fb
+1
-1
Submodule tools/XenonRecomp updated: 0fc545a6e2...cd6fcb33bd
Reference in New Issue
Block a user