mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-27 21:01:37 +00:00
Merge branch 'options-menu-and-installer' of https://github.com/hedge-dev/UnleashedRecomp into options-menu-and-installer
This commit is contained in:
commit
7e701ca516
16 changed files with 620 additions and 46 deletions
|
|
@ -2,6 +2,7 @@ cmake_minimum_required (VERSION 3.20)
|
|||
|
||||
include($ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
|
||||
set(SWA_THIRDPARTY_ROOT ${CMAKE_SOURCE_DIR}/thirdparty)
|
||||
set(SWA_TOOLS_ROOT ${CMAKE_SOURCE_DIR}/tools)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
|
|
@ -14,9 +15,9 @@ endif()
|
|||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
add_subdirectory(${SWA_THIRDPARTY_ROOT})
|
||||
project("UnleashedRecomp-ALL")
|
||||
add_subdirectory(${SWA_TOOLS_ROOT})
|
||||
|
||||
include("thirdparty/PowerRecomp/cmake/bin2h.cmake")
|
||||
project("UnleashedRecomp-ALL")
|
||||
|
||||
# Include sub-projects.
|
||||
add_subdirectory("UnleashedRecompLib")
|
||||
|
|
|
|||
|
|
@ -3,6 +3,32 @@ set(TARGET_NAME "SWA")
|
|||
|
||||
option(SWA_XAUDIO2 "Use XAudio2 for audio playback" OFF)
|
||||
|
||||
function(BIN2C)
|
||||
cmake_parse_arguments(BIN2C_ARGS "" "TARGET_OBJ;SOURCE_FILE;DEST_FILE;ARRAY_TYPE;ARRAY_NAME" "" ${ARGN})
|
||||
|
||||
if(NOT BIN2C_ARGS_TARGET_OBJ)
|
||||
message(FATAL_ERROR "TARGET_OBJ not specified.")
|
||||
endif()
|
||||
|
||||
if(NOT BIN2C_ARGS_SOURCE_FILE)
|
||||
message(FATAL_ERROR "SOURCE_FILE not specified.")
|
||||
endif()
|
||||
|
||||
if(NOT BIN2C_ARGS_DEST_FILE)
|
||||
set(BIN2C_ARGS_DEST_FILE "${BIN2C_ARGS_SOURCE_FILE}")
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT "${BIN2C_ARGS_DEST_FILE}.c"
|
||||
COMMAND file_to_c "${BIN2C_ARGS_SOURCE_FILE}" "${BIN2C_ARGS_ARRAY_NAME}" "${BIN2C_ARGS_ARRAY_TYPE}" "${BIN2C_ARGS_DEST_FILE}.c" "${BIN2C_ARGS_DEST_FILE}.h"
|
||||
DEPENDS "${BIN2C_ARGS_SOURCE_FILE}" file_to_c
|
||||
BYPRODUCTS "${BIN2C_ARGS_DEST_FILE}.h"
|
||||
COMMENT "Generating binary header for ${BIN2C_ARGS_SOURCE_FILE}..."
|
||||
)
|
||||
|
||||
set_source_files_properties(${BIN2C_ARGS_DEST_FILE}.c PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
|
||||
target_sources(${BIN2C_ARGS_TARGET_OBJ} PRIVATE ${BIN2C_ARGS_DEST_FILE}.c)
|
||||
endfunction()
|
||||
|
||||
add_compile_options(
|
||||
/fp:strict
|
||||
-march=sandybridge
|
||||
|
|
@ -23,10 +49,6 @@ add_compile_definitions(
|
|||
_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR # Microsoft wtf?
|
||||
_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
# Generate icon bitmap header for SDL surface.
|
||||
BIN2H(SOURCE_FILE "../UnleashedRecompResources/images/game_icon.bmp" HEADER_FILE "res/icon.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_icon")
|
||||
BIN2H(SOURCE_FILE "../UnleashedRecompResources/images/game_icon_night.bmp" HEADER_FILE "res/icon_night.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_iconNight")
|
||||
|
||||
set(SWA_PRECOMPILED_HEADERS
|
||||
"stdafx.h"
|
||||
)
|
||||
|
|
@ -86,6 +108,7 @@ set(SWA_UI_CXX_SOURCES
|
|||
"ui/achievement_menu.cpp"
|
||||
"ui/achievement_overlay.cpp"
|
||||
"ui/installer_wizard.cpp"
|
||||
"ui/message_window.cpp"
|
||||
"ui/options_menu.cpp"
|
||||
"ui/sdl_listener.cpp"
|
||||
"ui/window.cpp"
|
||||
|
|
@ -107,18 +130,6 @@ set(SWA_INSTALL_CXX_SOURCES
|
|||
"install/hashes/update.cpp"
|
||||
)
|
||||
|
||||
set(INSTALLER_IMAGES_DIR "../UnleashedRecompResources/images/installer")
|
||||
BIN2H(SOURCE_FILE "${INSTALLER_IMAGES_DIR}/install_001.dds" HEADER_FILE "res/install_001_dds.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_install001DDS")
|
||||
BIN2H(SOURCE_FILE "${INSTALLER_IMAGES_DIR}/install_002.dds" HEADER_FILE "res/install_002_dds.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_install002DDS")
|
||||
BIN2H(SOURCE_FILE "${INSTALLER_IMAGES_DIR}/install_003.dds" HEADER_FILE "res/install_003_dds.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_install003DDS")
|
||||
BIN2H(SOURCE_FILE "${INSTALLER_IMAGES_DIR}/install_004.dds" HEADER_FILE "res/install_004_dds.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_install004DDS")
|
||||
BIN2H(SOURCE_FILE "${INSTALLER_IMAGES_DIR}/install_005.dds" HEADER_FILE "res/install_005_dds.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_install005DDS")
|
||||
BIN2H(SOURCE_FILE "${INSTALLER_IMAGES_DIR}/install_006.dds" HEADER_FILE "res/install_006_dds.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_install006DDS")
|
||||
BIN2H(SOURCE_FILE "${INSTALLER_IMAGES_DIR}/install_007.dds" HEADER_FILE "res/install_007_dds.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_install007DDS")
|
||||
BIN2H(SOURCE_FILE "${INSTALLER_IMAGES_DIR}/install_008.dds" HEADER_FILE "res/install_008_dds.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_install008DDS")
|
||||
BIN2H(SOURCE_FILE "${INSTALLER_IMAGES_DIR}/miles_electric_icon.dds" HEADER_FILE "res/miles_electric_icon_dds.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_milesElectricIconDDS")
|
||||
BIN2H(SOURCE_FILE "${INSTALLER_IMAGES_DIR}/arrow_circle.dds" HEADER_FILE "res/arrow_circle_dds.h" ARRAY_TYPE "unsigned char" VARIABLE_NAME "g_arrowCircleDDS")
|
||||
|
||||
set(LIBMSPACK_PATH ${SWA_THIRDPARTY_ROOT}/libmspack/libmspack/mspack)
|
||||
|
||||
set(LIBMSPACK_C_SOURCES
|
||||
|
|
@ -301,3 +312,20 @@ generate_aggregate_header(
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/api"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/api/SWA.h"
|
||||
)
|
||||
|
||||
set(RESOURCES_SOURCE_PATH "${PROJECT_SOURCE_DIR}/../UnleashedRecompResources")
|
||||
set(RESOURCES_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/res")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/achievements_menu/trophy.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/achievements_menu/trophy.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_trophy")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/arrow_circle.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/arrow_circle.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_arrow_circle")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_001.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_001.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_install_001")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_002.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_002.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_install_002")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_003.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_003.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_install_003")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_004.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_004.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_install_004")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_005.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_005.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_install_005")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_006.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_006.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_install_006")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_007.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_007.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_install_007")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_008.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_008.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_install_008")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/miles_electric_icon.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/miles_electric_icon.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_miles_electric_icon")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon.bmp" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_game_icon")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon_night.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon_night.bmp" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_game_icon_night")
|
||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/pause.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/pause.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_pause")
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <shader/shader_cache.h>
|
||||
#include <ui/achievement_menu.h>
|
||||
#include <ui/achievement_overlay.h>
|
||||
#include <ui/message_window.h>
|
||||
#include <ui/options_menu.h>
|
||||
#include <ui/installer_wizard.h>
|
||||
|
||||
|
|
@ -1066,6 +1067,7 @@ static void CreateImGuiBackend()
|
|||
|
||||
AchievementMenu::Init();
|
||||
AchievementOverlay::Init();
|
||||
MessageWindow::Init();
|
||||
OptionsMenu::Init();
|
||||
InstallerWizard::Init();
|
||||
|
||||
|
|
@ -1741,6 +1743,7 @@ static void DrawImGui()
|
|||
OptionsMenu::Draw();
|
||||
AchievementOverlay::Draw();
|
||||
InstallerWizard::Draw();
|
||||
MessageWindow::Draw();
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
|
|
|
|||
1
UnleashedRecomp/res/.gitignore
vendored
1
UnleashedRecomp/res/.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
|||
![Ww][Ii][Nn]32/
|
||||
*.c
|
||||
*.h
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
#include <string>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <span>
|
||||
#include <xbox.h>
|
||||
#include <xxhash.h>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
#include <gpu/imgui_common.h>
|
||||
#include <app.h>
|
||||
|
||||
#define PIXELS_TO_UV_COORDS(textureWidth, textureHeight, x, y, width, height) \
|
||||
std::make_tuple(ImVec2((float)x / (float)textureWidth, (float)y / (float)textureHeight), \
|
||||
ImVec2(((float)x + (float)width) / (float)textureWidth, ((float)y + (float)height) / (float)textureHeight))
|
||||
|
||||
#define GET_UV_COORDS(tuple) std::get<0>(tuple), std::get<1>(tuple)
|
||||
|
||||
static std::vector<std::unique_ptr<ImGuiCallbackData>> g_callbackData;
|
||||
static uint32_t g_callbackDataIndex = 0;
|
||||
|
||||
|
|
@ -150,7 +156,80 @@ static void DrawTextWithShadow(const ImFont* font, float fontSize, const ImVec2&
|
|||
|
||||
DrawTextWithOutline<float>(font, fontSize, { pos.x + offset, pos.y + offset }, shadowColour, text, radius, shadowColour);
|
||||
|
||||
drawList->AddText(font, fontSize, pos, colour, text);
|
||||
drawList->AddText(font, fontSize, pos, colour, text, nullptr);
|
||||
}
|
||||
|
||||
static float CalcWidestTextSize(const ImFont* font, float fontSize, std::span<std::string> strs)
|
||||
{
|
||||
auto result = 0.0f;
|
||||
|
||||
for (auto& str : strs)
|
||||
result = std::max(result, font->CalcTextSizeA(fontSize, FLT_MAX, 0, str.c_str()).x);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::vector<std::string> Split(const char* str, char delimiter)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
if (!str)
|
||||
return result;
|
||||
|
||||
const char* start = str;
|
||||
const char* current = str;
|
||||
|
||||
while (*current)
|
||||
{
|
||||
if (*current == delimiter)
|
||||
{
|
||||
result.emplace_back(start, current - start);
|
||||
start = current + 1;
|
||||
}
|
||||
|
||||
current++;
|
||||
}
|
||||
|
||||
result.emplace_back(start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, std::vector<std::string> lines)
|
||||
{
|
||||
auto x = 0.0f;
|
||||
auto y = 0.0f;
|
||||
|
||||
for (auto& str : lines)
|
||||
{
|
||||
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, str.c_str());
|
||||
|
||||
x = std::max(x, textSize.x);
|
||||
y += textSize.y + Scale(lineMargin);
|
||||
}
|
||||
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
static ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, const char* text)
|
||||
{
|
||||
return MeasureCentredParagraph(font, fontSize, lineMargin, Split(text, '\n'));
|
||||
}
|
||||
|
||||
static void DrawCentredParagraph(const ImFont* font, float fontSize, const ImVec2& centre, float lineMargin, const char* text, std::function<void(const char*, ImVec2)> drawMethod)
|
||||
{
|
||||
auto lines = Split(text, '\n');
|
||||
auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines);
|
||||
auto offsetY = 0.0f;
|
||||
|
||||
for (auto& str : lines)
|
||||
{
|
||||
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, str.c_str());
|
||||
|
||||
drawMethod(str.c_str(), ImVec2(/* X */ centre.x - textSize.x / 2, /* Y */ centre.y - paragraphSize.y / 2 + offsetY));
|
||||
|
||||
offsetY += textSize.y + Scale(lineMargin);
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawTextWithMarqueeShadow(const ImFont* font, float fontSize, const ImVec2& pos, const ImVec2& min, const ImVec2& max, ImU32 colour, const char* text, double time, double delay, double speed, float offset = 2.0f, float radius = 0.4f, ImU32 shadowColour = IM_COL32(0, 0, 0, 255))
|
||||
|
|
|
|||
|
|
@ -8,16 +8,16 @@
|
|||
#include <ui/imgui_utils.h>
|
||||
#include <ui/window.h>
|
||||
|
||||
#include <res/install_001_dds.h>
|
||||
#include <res/install_002_dds.h>
|
||||
#include <res/install_003_dds.h>
|
||||
#include <res/install_004_dds.h>
|
||||
#include <res/install_005_dds.h>
|
||||
#include <res/install_006_dds.h>
|
||||
#include <res/install_007_dds.h>
|
||||
#include <res/install_008_dds.h>
|
||||
#include <res/miles_electric_icon_dds.h>
|
||||
#include <res/arrow_circle_dds.h>
|
||||
#include <res/images/installer/install_001.dds.h>
|
||||
#include <res/images/installer/install_002.dds.h>
|
||||
#include <res/images/installer/install_003.dds.h>
|
||||
#include <res/images/installer/install_004.dds.h>
|
||||
#include <res/images/installer/install_005.dds.h>
|
||||
#include <res/images/installer/install_006.dds.h>
|
||||
#include <res/images/installer/install_007.dds.h>
|
||||
#include <res/images/installer/install_008.dds.h>
|
||||
#include <res/images/installer/miles_electric_icon.dds.h>
|
||||
#include <res/images/installer/arrow_circle.dds.h>
|
||||
|
||||
static constexpr double SCANLINES_ANIMATION_TIME = 0.0;
|
||||
static constexpr double SCANLINES_ANIMATION_DURATION = 15.0;
|
||||
|
|
@ -999,16 +999,16 @@ void InstallerWizard::Init()
|
|||
g_seuratFont = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 26.0f * FONT_SCALE);
|
||||
g_dfsogeistdFont = io.Fonts->AddFontFromFileTTF("DFSoGeiStd-W7.otf", 48.0f * FONT_SCALE);
|
||||
g_newRodinFont = io.Fonts->AddFontFromFileTTF("FOT-NewRodinPro-DB.otf", 20.0f * FONT_SCALE);
|
||||
g_installTextures[0] = LoadTexture(g_install001DDS, g_install001DDS_size);
|
||||
g_installTextures[1] = LoadTexture(g_install002DDS, g_install002DDS_size);
|
||||
g_installTextures[2] = LoadTexture(g_install003DDS, g_install003DDS_size);
|
||||
g_installTextures[3] = LoadTexture(g_install004DDS, g_install004DDS_size);
|
||||
g_installTextures[4] = LoadTexture(g_install005DDS, g_install005DDS_size);
|
||||
g_installTextures[5] = LoadTexture(g_install006DDS, g_install006DDS_size);
|
||||
g_installTextures[6] = LoadTexture(g_install007DDS, g_install007DDS_size);
|
||||
g_installTextures[7] = LoadTexture(g_install008DDS, g_install008DDS_size);
|
||||
g_milesElectricIcon = LoadTexture(g_milesElectricIconDDS, g_milesElectricIconDDS_size);
|
||||
g_arrowCircle = LoadTexture(g_arrowCircleDDS, g_arrowCircleDDS_size);
|
||||
g_installTextures[0] = LoadTexture(g_install_001, sizeof(g_install_001));
|
||||
g_installTextures[1] = LoadTexture(g_install_002, sizeof(g_install_002));
|
||||
g_installTextures[2] = LoadTexture(g_install_003, sizeof(g_install_003));
|
||||
g_installTextures[3] = LoadTexture(g_install_004, sizeof(g_install_004));
|
||||
g_installTextures[4] = LoadTexture(g_install_005, sizeof(g_install_005));
|
||||
g_installTextures[5] = LoadTexture(g_install_006, sizeof(g_install_006));
|
||||
g_installTextures[6] = LoadTexture(g_install_007, sizeof(g_install_007));
|
||||
g_installTextures[7] = LoadTexture(g_install_008, sizeof(g_install_008));
|
||||
g_milesElectricIcon = LoadTexture(g_miles_electric_icon, sizeof(g_miles_electric_icon));
|
||||
g_arrowCircle = LoadTexture(g_arrow_circle, sizeof(g_arrow_circle));
|
||||
}
|
||||
|
||||
void InstallerWizard::Draw()
|
||||
|
|
|
|||
335
UnleashedRecomp/ui/message_window.cpp
Normal file
335
UnleashedRecomp/ui/message_window.cpp
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
#include "message_window.h"
|
||||
#include "imgui_utils.h"
|
||||
#include <api/SWA.h>
|
||||
#include <gpu/video.h>
|
||||
#include <exports.h>
|
||||
#include <res/images/pause.dds.h>
|
||||
|
||||
constexpr double OVERLAY_CONTAINER_COMMON_MOTION_START = 0;
|
||||
constexpr double OVERLAY_CONTAINER_COMMON_MOTION_END = 11;
|
||||
constexpr double OVERLAY_CONTAINER_INTRO_FADE_START = 5;
|
||||
constexpr double OVERLAY_CONTAINER_INTRO_FADE_END = 9;
|
||||
constexpr double OVERLAY_CONTAINER_OUTRO_FADE_START = 0;
|
||||
constexpr double OVERLAY_CONTAINER_OUTRO_FADE_END = 4;
|
||||
|
||||
static bool g_isAwaitingResult = false;
|
||||
static bool g_isClosing = false;
|
||||
static bool g_isControlsVisible = false;
|
||||
|
||||
static int g_selectedRowIndex;
|
||||
static int g_foregroundCount;
|
||||
|
||||
static bool g_upWasHeld;
|
||||
static bool g_downWasHeld;
|
||||
|
||||
static double g_appearTime;
|
||||
static double g_controlsAppearTime;
|
||||
|
||||
static ImFont* g_fntSeurat;
|
||||
|
||||
static std::unique_ptr<GuestTexture> g_upSelectionCursor;
|
||||
|
||||
std::string g_text;
|
||||
int g_result;
|
||||
std::vector<std::string> g_buttons;
|
||||
int g_defaultButtonIndex;
|
||||
|
||||
bool DrawContainer(float appearTime, ImVec2 centre, ImVec2 max, bool isForeground = true)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
|
||||
ImVec2 _min = { centre.x - max.x, centre.y - max.y };
|
||||
ImVec2 _max = { centre.x + max.x, centre.y + max.y };
|
||||
|
||||
// Expand/retract animation.
|
||||
auto containerMotion = ComputeMotion(appearTime, OVERLAY_CONTAINER_COMMON_MOTION_START, OVERLAY_CONTAINER_COMMON_MOTION_END);
|
||||
|
||||
if (g_isClosing)
|
||||
{
|
||||
_min.x = Hermite(_min.x, centre.x, containerMotion);
|
||||
_max.x = Hermite(_max.x, centre.x, containerMotion);
|
||||
_min.y = Hermite(_min.y, centre.y, containerMotion);
|
||||
_max.y = Hermite(_max.y, centre.y, containerMotion);
|
||||
}
|
||||
else
|
||||
{
|
||||
_min.x = Hermite(centre.x, _min.x, containerMotion);
|
||||
_max.x = Hermite(centre.x, _max.x, containerMotion);
|
||||
_min.y = Hermite(centre.y, _min.y, containerMotion);
|
||||
_max.y = Hermite(centre.y, _max.y, containerMotion);
|
||||
}
|
||||
|
||||
auto vertices = GetPauseContainerVertices(_min, _max);
|
||||
|
||||
// Transparency fade animation.
|
||||
auto colourMotion = g_isClosing
|
||||
? ComputeMotion(appearTime, OVERLAY_CONTAINER_OUTRO_FADE_START, OVERLAY_CONTAINER_OUTRO_FADE_END)
|
||||
: ComputeMotion(appearTime, OVERLAY_CONTAINER_INTRO_FADE_START, OVERLAY_CONTAINER_INTRO_FADE_END);
|
||||
|
||||
auto alpha = g_isClosing
|
||||
? Lerp(1, 0, colourMotion)
|
||||
: Lerp(0, 1, colourMotion);
|
||||
|
||||
if (!isForeground)
|
||||
g_foregroundCount++;
|
||||
|
||||
if (isForeground)
|
||||
drawList->AddRectFilled({ 0.0f, 0.0f }, ImGui::GetIO().DisplaySize, IM_COL32(0, 0, 0, 223 * (g_foregroundCount ? 1 : alpha)));
|
||||
|
||||
auto colShadow = IM_COL32(0, 0, 0, 156 * alpha);
|
||||
auto colGradientTop = IM_COL32(197, 194, 197, 200 * alpha);
|
||||
auto colGradientBottom = IM_COL32(115, 113, 115, 236 * alpha);
|
||||
|
||||
// Draw vertices with gradient.
|
||||
SetGradient(_min, _max, colGradientTop, colGradientBottom);
|
||||
drawList->AddConvexPolyFilled(vertices.data(), vertices.size(), IM_COL32(255, 255, 255, 255 * alpha));
|
||||
ResetGradient();
|
||||
|
||||
// Draw outline.
|
||||
drawList->AddPolyline
|
||||
(
|
||||
vertices.data(),
|
||||
vertices.size(),
|
||||
IM_COL32(247, 247, 247, 255 * alpha),
|
||||
true,
|
||||
Scale(2.5f)
|
||||
);
|
||||
|
||||
// Offset vertices to draw 3D effect lines.
|
||||
for (int i = 0; i < vertices.size(); i++)
|
||||
{
|
||||
vertices[i].x -= Scale(0.4f);
|
||||
vertices[i].y -= Scale(0.2f);
|
||||
}
|
||||
|
||||
auto colLineTop = IM_COL32(165, 170, 165, 230 * alpha);
|
||||
auto colLineBottom = IM_COL32(190, 190, 190, 230 * alpha);
|
||||
auto lineThickness = Scale(1.0f);
|
||||
|
||||
// Top left corner bottom to top left corner top.
|
||||
drawList->AddLine(vertices[0], vertices[1], colLineTop, lineThickness * 0.5f);
|
||||
|
||||
// Top left corner bottom to bottom left.
|
||||
drawList->AddRectFilledMultiColor({ vertices[0].x - 0.2f, vertices[0].y }, { vertices[6].x + lineThickness - 0.2f, vertices[6].y }, colLineTop, colLineTop, colLineBottom, colLineBottom);
|
||||
|
||||
// Top left corner top to top right.
|
||||
drawList->AddLine(vertices[1], vertices[2], colLineTop, lineThickness);
|
||||
|
||||
drawList->PushClipRect(_min, _max);
|
||||
|
||||
return containerMotion >= 1.0f && !g_isClosing;
|
||||
}
|
||||
|
||||
void DrawButton(int rowIndex, float yOffset, float width, float height, std::string& text)
|
||||
{
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
|
||||
auto clipRectMin = drawList->GetClipRectMin();
|
||||
auto clipRectMax = drawList->GetClipRectMax();
|
||||
|
||||
ImVec2 min = { clipRectMin.x + ((clipRectMax.x - clipRectMin.x) - width) / 2, clipRectMin.y + height * rowIndex + yOffset };
|
||||
ImVec2 max = { min.x + width, min.y + height };
|
||||
|
||||
bool isSelected = rowIndex == g_selectedRowIndex;
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
static auto breatheStart = ImGui::GetTime();
|
||||
auto alpha = Lerp(1.0f, 0.75f, (sin((ImGui::GetTime() - breatheStart) * (2.0f * M_PI / (55.0f / 60.0f))) + 1.0f) / 2.0f);
|
||||
auto colour = IM_COL32(255, 255, 255, 255 * alpha);
|
||||
|
||||
auto width = Scale(11);
|
||||
auto left = PIXELS_TO_UV_COORDS(128, 128, 0, 0, 11, 50);
|
||||
auto centre = PIXELS_TO_UV_COORDS(128, 128, 11, 0, 8, 50);
|
||||
auto right = PIXELS_TO_UV_COORDS(128, 128, 19, 0, 11, 50);
|
||||
|
||||
drawList->AddImage(g_upSelectionCursor.get(), min, { min.x + width, max.y }, GET_UV_COORDS(left), colour);
|
||||
drawList->AddImage(g_upSelectionCursor.get(), { min.x + width, min.y }, { max.x - width, max.y }, GET_UV_COORDS(centre), colour);
|
||||
drawList->AddImage(g_upSelectionCursor.get(), { max.x - width, min.y }, max, GET_UV_COORDS(right), colour);
|
||||
}
|
||||
|
||||
auto fontSize = Scale(28);
|
||||
auto textSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, text.c_str());
|
||||
|
||||
DrawTextWithShadow
|
||||
(
|
||||
g_fntSeurat,
|
||||
fontSize,
|
||||
{ /* X */ min.x + ((max.x - min.x) - textSize.x) / 2, /* Y */ min.y + ((max.y - min.y) - textSize.y) / 2 },
|
||||
isSelected ? IM_COL32(255, 128, 0, 255) : IM_COL32(255, 255, 255, 255),
|
||||
text.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
static void ResetSelection()
|
||||
{
|
||||
g_selectedRowIndex = g_defaultButtonIndex;
|
||||
g_upWasHeld = false;
|
||||
g_downWasHeld = false;
|
||||
}
|
||||
|
||||
void MessageWindow::Init()
|
||||
{
|
||||
auto& io = ImGui::GetIO();
|
||||
|
||||
constexpr float FONT_SCALE = 2.0f;
|
||||
|
||||
g_fntSeurat = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 28.0f * FONT_SCALE);
|
||||
|
||||
g_upSelectionCursor = LoadTexture(g_pause, sizeof(g_pause));
|
||||
}
|
||||
|
||||
void MessageWindow::Draw()
|
||||
{
|
||||
if (!s_isVisible)
|
||||
return;
|
||||
|
||||
auto pInputState = SWA::CInputState::GetInstance();
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
auto& res = ImGui::GetIO().DisplaySize;
|
||||
|
||||
ImVec2 centre = { res.x / 2, res.y / 2 };
|
||||
|
||||
auto fontSize = Scale(28);
|
||||
auto textSize = MeasureCentredParagraph(g_fntSeurat, fontSize, 5, g_text.c_str());
|
||||
auto textMarginX = Scale(32);
|
||||
auto textMarginY = Scale(40);
|
||||
|
||||
if (DrawContainer(g_appearTime, centre, { textSize.x / 2 + textMarginX, textSize.y / 2 + textMarginY }, !g_isControlsVisible))
|
||||
{
|
||||
DrawCentredParagraph
|
||||
(
|
||||
g_fntSeurat,
|
||||
fontSize,
|
||||
{ centre.x, centre.y + Scale(3) },
|
||||
5,
|
||||
g_text.c_str(),
|
||||
|
||||
[=](const char* str, ImVec2 pos)
|
||||
{
|
||||
DrawTextWithShadow(g_fntSeurat, fontSize, pos, IM_COL32(255, 255, 255, 255), str);
|
||||
}
|
||||
);
|
||||
|
||||
drawList->PopClipRect();
|
||||
|
||||
if (g_buttons.size())
|
||||
{
|
||||
auto itemWidth = std::max(Scale(162), Scale(CalcWidestTextSize(g_fntSeurat, fontSize, g_buttons)));
|
||||
auto itemHeight = Scale(57);
|
||||
auto windowMarginX = Scale(18);
|
||||
auto windowMarginY = Scale(25);
|
||||
|
||||
ImVec2 controlsMax = { /* X */ itemWidth / 2 + windowMarginX, /* Y */ itemHeight / 2 * g_buttons.size() + windowMarginY };
|
||||
|
||||
if (g_isControlsVisible && DrawContainer(g_controlsAppearTime, centre, controlsMax))
|
||||
{
|
||||
auto rowCount = 0;
|
||||
|
||||
for (auto& button : g_buttons)
|
||||
DrawButton(rowCount++, windowMarginY, itemWidth, itemHeight, button);
|
||||
|
||||
drawList->PopClipRect();
|
||||
|
||||
bool upIsHeld = pInputState->GetPadState().IsDown(SWA::eKeyState_DpadUp) ||
|
||||
pInputState->GetPadState().LeftStickVertical > 0.5f;
|
||||
|
||||
bool downIsHeld = pInputState->GetPadState().IsDown(SWA::eKeyState_DpadDown) ||
|
||||
pInputState->GetPadState().LeftStickVertical < -0.5f;
|
||||
|
||||
bool scrollUp = !g_upWasHeld && upIsHeld;
|
||||
bool scrollDown = !g_downWasHeld && downIsHeld;
|
||||
|
||||
if (scrollUp)
|
||||
{
|
||||
--g_selectedRowIndex;
|
||||
if (g_selectedRowIndex < 0)
|
||||
g_selectedRowIndex = rowCount - 1;
|
||||
}
|
||||
else if (scrollDown)
|
||||
{
|
||||
++g_selectedRowIndex;
|
||||
if (g_selectedRowIndex >= rowCount)
|
||||
g_selectedRowIndex = 0;
|
||||
}
|
||||
|
||||
if (scrollUp || scrollDown)
|
||||
Game_PlaySound("sys_actstg_pausecursor");
|
||||
|
||||
g_upWasHeld = upIsHeld;
|
||||
g_downWasHeld = downIsHeld;
|
||||
|
||||
if (pInputState->GetPadState().IsTapped(SWA::eKeyState_A))
|
||||
{
|
||||
g_result = g_selectedRowIndex;
|
||||
|
||||
Game_PlaySound("sys_actstg_pausedecide");
|
||||
MessageWindow::Close();
|
||||
}
|
||||
else if (pInputState->GetPadState().IsTapped(SWA::eKeyState_B))
|
||||
{
|
||||
g_result = -1;
|
||||
|
||||
Game_PlaySound("sys_actstg_pausecansel");
|
||||
MessageWindow::Close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!g_isControlsVisible && pInputState->GetPadState().IsTapped(SWA::eKeyState_A))
|
||||
{
|
||||
g_controlsAppearTime = ImGui::GetTime();
|
||||
g_isControlsVisible = true;
|
||||
|
||||
Game_PlaySound("sys_actstg_pausewinopen");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pInputState->GetPadState().IsTapped(SWA::eKeyState_A))
|
||||
MessageWindow::Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MessageWindow::Open(std::string text, int* result, std::span<std::string> buttons, int defaultButtonIndex)
|
||||
{
|
||||
if (!g_isAwaitingResult && *result == -1)
|
||||
{
|
||||
s_isVisible = true;
|
||||
g_isClosing = false;
|
||||
g_isControlsVisible = false;
|
||||
g_foregroundCount = 0;
|
||||
g_appearTime = ImGui::GetTime();
|
||||
g_controlsAppearTime = ImGui::GetTime();
|
||||
|
||||
g_text = text;
|
||||
g_buttons = std::vector(buttons.begin(), buttons.end());
|
||||
g_defaultButtonIndex = defaultButtonIndex;
|
||||
|
||||
ResetSelection();
|
||||
|
||||
Game_PlaySound("sys_actstg_pausewinopen");
|
||||
|
||||
g_isAwaitingResult = true;
|
||||
}
|
||||
|
||||
*result = g_result;
|
||||
|
||||
return !g_isAwaitingResult;
|
||||
}
|
||||
|
||||
void MessageWindow::Close()
|
||||
{
|
||||
if (!g_isClosing)
|
||||
{
|
||||
g_appearTime = ImGui::GetTime();
|
||||
g_controlsAppearTime = ImGui::GetTime();
|
||||
g_isClosing = true;
|
||||
g_isControlsVisible = false;
|
||||
g_isAwaitingResult = false;
|
||||
}
|
||||
|
||||
Game_PlaySound("sys_actstg_pausewinclose");
|
||||
}
|
||||
12
UnleashedRecomp/ui/message_window.h
Normal file
12
UnleashedRecomp/ui/message_window.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
class MessageWindow
|
||||
{
|
||||
public:
|
||||
inline static bool s_isVisible = false;
|
||||
|
||||
static void Init();
|
||||
static void Draw();
|
||||
static bool Open(std::string text, int* result, std::span<std::string> buttons = {}, int defaultButtonIndex = 0);
|
||||
static void Close();
|
||||
};
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <api/SWA.h>
|
||||
|
||||
struct OptionsMenu
|
||||
class OptionsMenu
|
||||
{
|
||||
public:
|
||||
inline static bool s_isVisible = false;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <res/icon.h>
|
||||
#include <res/icon_night.h>
|
||||
#include <res/images/game_icon.bmp.h>
|
||||
#include <res/images/game_icon_night.bmp.h>
|
||||
#include <ui/window_events.h>
|
||||
#include <user/config.h>
|
||||
|
||||
|
|
@ -47,11 +47,11 @@ public:
|
|||
{
|
||||
if (isNight)
|
||||
{
|
||||
SetIcon((void*)g_iconNight, g_iconNight_size);
|
||||
SetIcon(g_game_icon_night, sizeof(g_game_icon_night));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetIcon((void*)g_icon, g_icon_size);
|
||||
SetIcon(g_game_icon, sizeof(g_game_icon));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 79a2a18cc8013dd6d76d8300f703f19f6e0ec484
|
||||
Subproject commit b04e3bdcd9e76a0717cec69822f4eb01cd97d5c6
|
||||
2
thirdparty/PowerRecomp
vendored
2
thirdparty/PowerRecomp
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 675b482ec4852b873590fb999d24b426bade2b3a
|
||||
Subproject commit ea3e60cb0d618ec8d24cc745d72b1ac39cc722cc
|
||||
1
tools/CMakeLists.txt
Normal file
1
tools/CMakeLists.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(${SWA_TOOLS_ROOT}/file_to_c)
|
||||
8
tools/file_to_c/CMakeLists.txt
Normal file
8
tools/file_to_c/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
project("file_to_c")
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
add_executable(file_to_c "file_to_c.cpp")
|
||||
105
tools/file_to_c/file_to_c.cpp
Normal file
105
tools/file_to_c/file_to_c.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 RT64 Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
std::vector<char> read_file(const char* path) {
|
||||
std::ifstream input_file{path, std::ios::binary};
|
||||
std::vector<char> ret{};
|
||||
|
||||
if (!input_file.good()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get the length of the file
|
||||
input_file.seekg(0, std::ios::end);
|
||||
ret.resize(input_file.tellg());
|
||||
|
||||
// Read the file contents into the vector
|
||||
input_file.seekg(0, std::ios::beg);
|
||||
input_file.read(ret.data(), ret.size());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void create_parent_if_needed(const char* path) {
|
||||
std::filesystem::path parent_path = std::filesystem::path{path}.parent_path();
|
||||
if (!parent_path.empty()) {
|
||||
std::filesystem::create_directories(parent_path);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
if (argc != 6) {
|
||||
printf("Usage: %s [input file] [array name] [array type] [output C file] [output C header]\n", argv[0]);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
const char* input_path = argv[1];
|
||||
const char* array_name = argv[2];
|
||||
const char* array_type = argv[3];
|
||||
const char* output_c_path = argv[4];
|
||||
const char* output_h_path = argv[5];
|
||||
|
||||
// Read the input file's contents
|
||||
std::vector<char> contents = read_file(input_path);
|
||||
|
||||
if (contents.empty()) {
|
||||
fprintf(stderr, "Failed to open file %s! (Or it's empty)\n", input_path);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Create the output directories if they don't exist
|
||||
create_parent_if_needed(output_c_path);
|
||||
create_parent_if_needed(output_h_path);
|
||||
|
||||
// Write the C file with the array
|
||||
{
|
||||
std::ofstream output_c_file{output_c_path};
|
||||
output_c_file << "extern " << array_type << " " << array_name << "[" << contents.size() << "];\n";
|
||||
output_c_file << array_type << " " << array_name << "[" << contents.size() << "] = {";
|
||||
|
||||
for (char x : contents) {
|
||||
output_c_file << (int)x << ", ";
|
||||
}
|
||||
|
||||
output_c_file << "};\n";
|
||||
}
|
||||
|
||||
// Write the header file with the extern array
|
||||
{
|
||||
std::ofstream output_h_file{output_h_path};
|
||||
output_h_file <<
|
||||
"#ifdef __cplusplus\n"
|
||||
" extern \"C\" {\n"
|
||||
"#endif\n"
|
||||
"extern " << array_type << " " << array_name << "[" << contents.size() << "];\n"
|
||||
"#ifdef __cplusplus\n"
|
||||
" }\n"
|
||||
"#endif\n";
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue