mirror of
https://github.com/Mr-Wiseguy/Zelda64Recomp.git
synced 2024-11-16 19:09:15 +01:00
Added function patching, began reorganizing UI code, added native file dialog library
This commit is contained in:
parent
91611c9c33
commit
398988a961
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
# Output C files
|
# Output C files
|
||||||
RecompiledFuncs/
|
RecompiledFuncs/
|
||||||
|
RecompiledPatches/
|
||||||
|
|
||||||
# Linux build output
|
# Linux build output
|
||||||
build/
|
build/
|
||||||
@ -43,6 +44,7 @@ bld/
|
|||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
|
vcpkg_installed/
|
||||||
|
|
||||||
# Runtime files
|
# Runtime files
|
||||||
imgui.ini
|
imgui.ini
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -4,3 +4,6 @@
|
|||||||
[submodule "thirdparty/RmlUi"]
|
[submodule "thirdparty/RmlUi"]
|
||||||
path = thirdparty/RmlUi
|
path = thirdparty/RmlUi
|
||||||
url = https://github.com/mikke89/RmlUi
|
url = https://github.com/mikke89/RmlUi
|
||||||
|
[submodule "thirdparty/nativefiledialog-extended"]
|
||||||
|
path = thirdparty/nativefiledialog-extended
|
||||||
|
url = https://github.com/btzy/nativefiledialog-extended
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
project(MMRecomp)
|
project(MMRecomp)
|
||||||
|
set(CMAKE_C_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
@ -16,14 +17,13 @@ find_package(Freetype REQUIRED)
|
|||||||
|
|
||||||
add_subdirectory(${CMAKE_SOURCE_DIR}/../mupen_rt64/mupen64plus-video-rt64 ${CMAKE_BINARY_DIR}/rt64)
|
add_subdirectory(${CMAKE_SOURCE_DIR}/../mupen_rt64/mupen64plus-video-rt64 ${CMAKE_BINARY_DIR}/rt64)
|
||||||
add_subdirectory(${CMAKE_SOURCE_DIR}/thirdparty/RmlUi)
|
add_subdirectory(${CMAKE_SOURCE_DIR}/thirdparty/RmlUi)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/thirdparty/nativefiledialog-extended)
|
||||||
|
|
||||||
target_include_directories(rt64 PRIVATE ${CMAKE_BINARY_DIR}/rt64/src)
|
target_include_directories(rt64 PRIVATE ${CMAKE_BINARY_DIR}/rt64/src)
|
||||||
get_target_property(RT64_BASENAME rt64 OUTPUT_NAME)
|
get_target_property(RT64_BASENAME rt64 OUTPUT_NAME)
|
||||||
set(RT64_DLL ${RT64_BASENAME}${CMAKE_SHARED_LIBRARY_SUFFIX})
|
set(RT64_DLL ${RT64_BASENAME}${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||||
|
|
||||||
file(GLOB FUNC_C_SOURCES ${CMAKE_SOURCE_DIR}/RecompiledFuncs/*.c)
|
# RecompiledFuncs - Library containing the primary recompiler output
|
||||||
file(GLOB FUNC_CXX_SOURCES ${CMAKE_SOURCE_DIR}/RecompiledFuncs/*.cpp)
|
|
||||||
|
|
||||||
add_library(RecompiledFuncs STATIC)
|
add_library(RecompiledFuncs STATIC)
|
||||||
|
|
||||||
target_compile_options(RecompiledFuncs PRIVATE
|
target_compile_options(RecompiledFuncs PRIVATE
|
||||||
@ -35,8 +35,44 @@ target_include_directories(RecompiledFuncs PRIVATE
|
|||||||
${CMAKE_SOURCE_DIR}/include
|
${CMAKE_SOURCE_DIR}/include
|
||||||
)
|
)
|
||||||
|
|
||||||
|
file(GLOB FUNC_C_SOURCES ${CMAKE_SOURCE_DIR}/RecompiledFuncs/*.c)
|
||||||
|
file(GLOB FUNC_CXX_SOURCES ${CMAKE_SOURCE_DIR}/RecompiledFuncs/*.cpp)
|
||||||
|
|
||||||
target_sources(RecompiledFuncs PRIVATE ${FUNC_C_SOURCES} ${FUNC_CXX_SOURCES})
|
target_sources(RecompiledFuncs PRIVATE ${FUNC_C_SOURCES} ${FUNC_CXX_SOURCES})
|
||||||
|
|
||||||
|
# PatchesLib - Library containing the recompiled output for any custom function patches
|
||||||
|
add_library(PatchesLib STATIC)
|
||||||
|
|
||||||
|
target_compile_options(PatchesLib PRIVATE
|
||||||
|
# -Wno-unused-but-set-variable
|
||||||
|
-fno-strict-aliasing
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(PatchesLib PRIVATE
|
||||||
|
${CMAKE_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(PatchesLib PRIVATE
|
||||||
|
${CMAKE_SOURCE_DIR}/RecompiledPatches/patches.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Build patches elf
|
||||||
|
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/patches/patches.elf
|
||||||
|
COMMAND make
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/patches
|
||||||
|
BYPRODUCTS ${CMAKE_SOURCE_DIR}/patches/patches.bin}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Recompile patches elf into patches.c
|
||||||
|
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/RecompiledPatches/patches.c
|
||||||
|
COMMAND RecompPort patches.toml
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
DEPENDS ${CMAKE_SOURCE_DIR}/patches/patches.elf
|
||||||
|
)
|
||||||
|
|
||||||
|
# Main executable
|
||||||
|
add_executable(MMRecomp)
|
||||||
|
|
||||||
set (SOURCES
|
set (SOURCES
|
||||||
${CMAKE_SOURCE_DIR}/portultra/audio.cpp
|
${CMAKE_SOURCE_DIR}/portultra/audio.cpp
|
||||||
${CMAKE_SOURCE_DIR}/portultra/events.cpp
|
${CMAKE_SOURCE_DIR}/portultra/events.cpp
|
||||||
@ -67,7 +103,9 @@ set (SOURCES
|
|||||||
${CMAKE_SOURCE_DIR}/src/sp.cpp
|
${CMAKE_SOURCE_DIR}/src/sp.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/vi.cpp
|
${CMAKE_SOURCE_DIR}/src/vi.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/main/main.cpp
|
${CMAKE_SOURCE_DIR}/src/main/main.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ui.cpp
|
|
||||||
|
${CMAKE_SOURCE_DIR}/src/ui/ui_renderer.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/ui/ui_events.cpp
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/rsp/aspMain.cpp
|
${CMAKE_SOURCE_DIR}/rsp/aspMain.cpp
|
||||||
${CMAKE_SOURCE_DIR}/rsp/njpgdspMain.cpp
|
${CMAKE_SOURCE_DIR}/rsp/njpgdspMain.cpp
|
||||||
@ -75,8 +113,6 @@ set (SOURCES
|
|||||||
${CMAKE_SOURCE_DIR}/thirdparty/RmlUi/Backends/RmlUi_Platform_SDL.cpp
|
${CMAKE_SOURCE_DIR}/thirdparty/RmlUi/Backends/RmlUi_Platform_SDL.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(MMRecomp)
|
|
||||||
|
|
||||||
target_include_directories(MMRecomp PRIVATE
|
target_include_directories(MMRecomp PRIVATE
|
||||||
${CMAKE_SOURCE_DIR}/include
|
${CMAKE_SOURCE_DIR}/include
|
||||||
${CMAKE_SOURCE_DIR}/thirdparty
|
${CMAKE_SOURCE_DIR}/thirdparty
|
||||||
@ -100,12 +136,14 @@ target_link_directories(MMRecomp PRIVATE
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(MMRecomp PRIVATE
|
target_link_libraries(MMRecomp PRIVATE
|
||||||
|
PatchesLib
|
||||||
RecompiledFuncs
|
RecompiledFuncs
|
||||||
SDL2
|
SDL2
|
||||||
rt64
|
rt64
|
||||||
Freetype::Freetype
|
Freetype::Freetype
|
||||||
RmlCore
|
RmlCore
|
||||||
RmlDebugger
|
RmlDebugger
|
||||||
|
nfd
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO fix the RT64 CMake script so that this doesn't need to be duplicated here
|
# TODO fix the RT64 CMake script so that this doesn't need to be duplicated here
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
<rml>
|
|
||||||
<head>
|
|
||||||
<title>Demo</title>
|
|
||||||
<link type="text/template" href="window.rml" />
|
|
||||||
<style>
|
|
||||||
body
|
|
||||||
{
|
|
||||||
width: 300dp;
|
|
||||||
height: 225dp;
|
|
||||||
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#title_bar div#icon
|
|
||||||
{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#content
|
|
||||||
{
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body template="window">
|
|
||||||
This is a sample.<br/>
|
|
||||||
Wiseguy was here
|
|
||||||
</body>
|
|
||||||
</rml>
|
|
File diff suppressed because one or more lines are too long
134
assets/invader_spritesheet.rcss
Normal file
134
assets/invader_spritesheet.rcss
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
@spritesheet theme
|
||||||
|
{
|
||||||
|
src: invader.tga;
|
||||||
|
|
||||||
|
/* For high dpi screens, designates the scaling it is intended to be shown at. */
|
||||||
|
resolution: 1x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The following specifies a list of sprite names and associated rectangles into the image given above.
|
||||||
|
Any sprite given here can be specified in a decorator. Their names must be globally unique.
|
||||||
|
Rectangles are specified as: x y width height. With the origin assumed to be at the top left corner.
|
||||||
|
*/
|
||||||
|
title-bar-l: 147px 0px 82px 85px;
|
||||||
|
title-bar-c: 229px 0px 1px 85px;
|
||||||
|
title-bar-r: 231px 0px 15px 85px;
|
||||||
|
|
||||||
|
/* huditems are vertically flipped titlebars */
|
||||||
|
huditem-l: 147px 55px 82px -55px;
|
||||||
|
huditem-c: 229px 55px 1px -55px;
|
||||||
|
huditem-r: 231px 55px 15px -55px;
|
||||||
|
|
||||||
|
icon-help: 128px 152px 51px 39px;
|
||||||
|
icon-invader: 179px 152px 51px 39px;
|
||||||
|
icon-game: 230px 152px 51px 39px;
|
||||||
|
icon-hiscore: 281px 152px 51px 39px;
|
||||||
|
icon-waves: 332px 152px 51px 39px;
|
||||||
|
icon-flag: 336px 191px 51px 39px;
|
||||||
|
icon-lives: 383px 152px 51px 39px;
|
||||||
|
icon-score: 434px 152px 51px 39px;
|
||||||
|
|
||||||
|
window-tl: 0px 0px 133px 140px;
|
||||||
|
window-t: 134px 0px 1px 140px;
|
||||||
|
window-tr: 136px 0px 10px 140px;
|
||||||
|
window-l: 0px 139px 10px 1px;
|
||||||
|
window-c: 11px 139px 1px 1px;
|
||||||
|
window-r: 10px 139px -10px 1px; /* mirrored left */
|
||||||
|
window-bl: 0px 140px 11px 11px;
|
||||||
|
window-b: 11px 140px 1px 11px;
|
||||||
|
window-br: 136px 140px 10px 11px;
|
||||||
|
|
||||||
|
button: 247px 0px 159px 45px;
|
||||||
|
button-hover: 247px 45px 159px 45px;
|
||||||
|
button-active: 247px 90px 159px 45px;
|
||||||
|
|
||||||
|
button-inner: 259px 19px 135px 1px;
|
||||||
|
button-inner-hover: 259px 64px 135px 1px;
|
||||||
|
button-inner-active: 259px 109px 135px 1px;
|
||||||
|
|
||||||
|
text-l: 162px 192px 14px 31px;
|
||||||
|
text-c: 176px 192px 1px 31px;
|
||||||
|
textarea: 162px 193px 145px 31px;
|
||||||
|
textarea-inner: 173px 206px 127px 10px;
|
||||||
|
|
||||||
|
selectbox-tl: 281px 275px 11px 9px;
|
||||||
|
selectbox-t: 292px 275px 1px 9px;
|
||||||
|
selectbox-tr: 294px 275px 11px 9px;
|
||||||
|
selectbox-l: 281px 283px 11px 1px;
|
||||||
|
selectbox-c: 292px 283px 1px 1px;
|
||||||
|
selectbox-bl: 281px 285px 11px 11px;
|
||||||
|
selectbox-b: 292px 285px 1px 11px;
|
||||||
|
selectbox-br: 294px 285px 11px 11px;
|
||||||
|
|
||||||
|
selectvalue: 162px 192px 145px 37px;
|
||||||
|
selectvalue-hover: 162px 230px 145px 37px;
|
||||||
|
selectarrow: 307px 192px 30px 37px;
|
||||||
|
selectarrow-hover: 307px 230px 30px 37px;
|
||||||
|
selectarrow-active: 307px 268px 30px 37px;
|
||||||
|
|
||||||
|
radio: 407px 0px 30px 30px;
|
||||||
|
radio-hover: 437px 0px 30px 30px;
|
||||||
|
radio-active: 467px 0px 30px 30px;
|
||||||
|
radio-checked: 407px 30px 30px 30px;
|
||||||
|
radio-checked-hover: 437px 30px 30px 30px;
|
||||||
|
radio-checked-active: 467px 30px 30px 30px;
|
||||||
|
|
||||||
|
checkbox: 407px 60px 30px 30px;
|
||||||
|
checkbox-hover: 437px 60px 30px 30px;
|
||||||
|
checkbox-active: 467px 60px 30px 30px;
|
||||||
|
checkbox-checked: 407px 90px 30px 30px;
|
||||||
|
checkbox-checked-hover: 437px 90px 30px 30px;
|
||||||
|
checkbox-checked-active: 467px 90px 30px 30px;
|
||||||
|
|
||||||
|
tableheader-l: 127px 192px 16px 31px;
|
||||||
|
tableheader-c: 143px 192px 2px 31px;
|
||||||
|
tableheader-r: 145px 192px 15px 31px;
|
||||||
|
|
||||||
|
expand: 3px 232px 17px 17px;
|
||||||
|
expand-hover: 21px 232px 17px 17px;
|
||||||
|
expand-active: 39px 232px 17px 17px;
|
||||||
|
expand-collapsed: 3px 250px 17px 17px;
|
||||||
|
expand-collapsed-hover: 21px 250px 17px 17px;
|
||||||
|
expand-collapsed-active: 39px 250px 17px 17px;
|
||||||
|
|
||||||
|
slidertrack-t: 70px 199px 27px 2px;
|
||||||
|
slidertrack-c: 70px 201px 27px 1px;
|
||||||
|
slidertrack-b: 70px 202px 27px 2px;
|
||||||
|
|
||||||
|
sliderbar-t: 56px 152px 23px 23px;
|
||||||
|
sliderbar-c: 56px 175px 23px 1px;
|
||||||
|
sliderbar-b: 56px 176px 23px 22px;
|
||||||
|
sliderbar-hover-t: 80px 152px 23px 23px;
|
||||||
|
sliderbar-hover-c: 80px 175px 23px 1px;
|
||||||
|
sliderbar-hover-b: 80px 176px 23px 22px;
|
||||||
|
sliderbar-active-t: 104px 152px 23px 23px;
|
||||||
|
sliderbar-active-c: 104px 175px 23px 1px;
|
||||||
|
sliderbar-active-b: 104px 176px 23px 22px;
|
||||||
|
|
||||||
|
sliderarrowdec: 0px 152px 27px 24px;
|
||||||
|
sliderarrowdec-hover: 0px 177px 27px 24px;
|
||||||
|
sliderarrowdec-active: 0px 202px 27px 24px;
|
||||||
|
|
||||||
|
sliderarrowinc: 28px 152px 27px 24px;
|
||||||
|
sliderarrowinc-hover: 28px 177px 27px 24px;
|
||||||
|
sliderarrowinc-active: 28px 202px 27px 24px;
|
||||||
|
|
||||||
|
range-track: 219px 194px 3px 32px;
|
||||||
|
range-track-inner: 220px 204px 1px 14px;
|
||||||
|
range-bar: 127px 191px 34px 32px;
|
||||||
|
range-dec: 3px 232px 17px 17px;
|
||||||
|
range-dec-hover: 21px 232px 17px 17px;
|
||||||
|
range-dec-active: 39px 232px 17px 17px;
|
||||||
|
range-inc: 3px 250px 17px 17px;
|
||||||
|
range-inc-hover: 21px 250px 17px 17px;
|
||||||
|
range-inc-active: 39px 250px 17px 17px;
|
||||||
|
|
||||||
|
progress-l: 103px 267px 13px 34px;
|
||||||
|
progress-c: 116px 267px 54px 34px;
|
||||||
|
progress-r: 170px 267px 13px 34px;
|
||||||
|
progress-fill-l: 110px 302px 6px 34px;
|
||||||
|
progress-fill-c: 140px 302px 6px 34px;
|
||||||
|
progress-fill-r: 170px 302px 6px 34px;
|
||||||
|
gauge: 0px 271px 100px 86px;
|
||||||
|
gauge-fill: 0px 356px 100px 86px;
|
||||||
|
}
|
22
assets/launcher.rml
Normal file
22
assets/launcher.rml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<rml>
|
||||||
|
<head>
|
||||||
|
<title>Launcher</title>
|
||||||
|
<link type="text/rcss" href="rml.rcss"/>
|
||||||
|
<link type="text/rcss" href="invader_spritesheet.rcss"/>
|
||||||
|
<link type="text/rcss" href="invader.rcss"/>
|
||||||
|
<style>
|
||||||
|
body
|
||||||
|
{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="window">
|
||||||
|
<button onclick="start_game" style="align-self: center;">Start Game</button>
|
||||||
|
This is a sample.<br/>
|
||||||
|
Test text
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</rml>
|
@ -1,19 +0,0 @@
|
|||||||
<template name="window" content="content">
|
|
||||||
<head>
|
|
||||||
<link type="text/rcss" href="rml.rcss"/>
|
|
||||||
<link type="text/rcss" href="invader.rcss"/>
|
|
||||||
</head>
|
|
||||||
<body class="window">
|
|
||||||
<div id="title_bar">
|
|
||||||
<handle move_target="#document">
|
|
||||||
<div id="icon"></div>
|
|
||||||
<span id="title">Title</span>
|
|
||||||
</handle>
|
|
||||||
</div>
|
|
||||||
<div id="window">
|
|
||||||
<div id="content">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<handle size_target="#document" style="position: absolute; width: 16dp; height: 16dp; bottom: 0px; right: 0px; cursor: resize;"></handle>
|
|
||||||
</body>
|
|
||||||
</template>
|
|
@ -1,9 +1,25 @@
|
|||||||
#ifndef __RECOMP_UI__
|
#ifndef __RECOMP_UI__
|
||||||
#define __RECOMP_UI__
|
#define __RECOMP_UI__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "SDL.h"
|
#include "SDL.h"
|
||||||
|
|
||||||
void queue_event(const SDL_Event& event);
|
void queue_event(const SDL_Event& event);
|
||||||
bool try_deque_event(SDL_Event& out);
|
bool try_deque_event(SDL_Event& out);
|
||||||
|
|
||||||
|
namespace Rml {
|
||||||
|
class ElementDocument;
|
||||||
|
class EventListenerInstancer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Rml::EventListenerInstancer> make_event_listener_instancer();
|
||||||
|
|
||||||
|
enum class Menu {
|
||||||
|
Launcher,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_current_menu(Menu menu);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -125,8 +125,8 @@ auto RSP::CFC2(r32& rt, u8 rd) -> void {
|
|||||||
if constexpr (Accuracy::RSP::SISD) {
|
if constexpr (Accuracy::RSP::SISD) {
|
||||||
rt = 0;
|
rt = 0;
|
||||||
for (u32 n = 0; n < 8; n++) {
|
for (u32 n = 0; n < 8; n++) {
|
||||||
rt |= lo.get(n) << 0 + n;
|
rt |= lo.get(n) << (0 + n);
|
||||||
rt |= hi.get(n) << 8 + n;
|
rt |= hi.get(n) << (8 + n);
|
||||||
}
|
}
|
||||||
rt = s16(rt);
|
rt = s16(rt);
|
||||||
}
|
}
|
||||||
@ -151,8 +151,8 @@ auto RSP::CTC2(cr32& rt, u8 rd) -> void {
|
|||||||
|
|
||||||
if constexpr (Accuracy::RSP::SISD) {
|
if constexpr (Accuracy::RSP::SISD) {
|
||||||
for (u32 n = 0; n < 8; n++) {
|
for (u32 n = 0; n < 8; n++) {
|
||||||
lo->set(n, rt & 1 << 0 + n);
|
lo->set(n, rt & 1 << (0 + n));
|
||||||
hi->set(n, rt & 1 << 8 + n);
|
hi->set(n, rt & 1 << (8 + n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
patches.toml
Normal file
9
patches.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Config file for recompiling patches for the Majora's Mask NTSC 1.0 Recompilation.
|
||||||
|
|
||||||
|
[input]
|
||||||
|
# Paths are relative to the location of this config file.
|
||||||
|
elf_path = "patches/patches.elf"
|
||||||
|
output_func_path = "RecompiledPatches"
|
||||||
|
single_file_output = true
|
||||||
|
# Allow absolute symbols to be used as jump targets
|
||||||
|
use_absolute_symbols = true
|
5
patches/.gitignore
vendored
Normal file
5
patches/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
*.d
|
||||||
|
*.o
|
||||||
|
*.elf
|
||||||
|
*.bin
|
||||||
|
./funcs.h
|
32
patches/Makefile
Normal file
32
patches/Makefile
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
TARGET = patches.elf
|
||||||
|
|
||||||
|
CC := clang
|
||||||
|
LD := ld.lld
|
||||||
|
OBJCOPY := llvm-objcopy
|
||||||
|
|
||||||
|
CFLAGS := -target mips -mips2 -mabi=32 -O2 -mno-odd-spreg -fomit-frame-pointer -G0 -Wall -Wextra -Wno-incompatible-library-redeclaration -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-variable
|
||||||
|
CPPFLAGS := -nostdinc -D_LANGUAGE_C -I ../../mm/include -I ../../mm/src -I ../../mm/build -I ../../mm/assets
|
||||||
|
LDFLAGS := -nostdlib -T patches.ld -T syms.ld
|
||||||
|
BINFLAGS := -O binary
|
||||||
|
|
||||||
|
C_SRCS := $(wildcard *.c)
|
||||||
|
C_OBJS := $(C_SRCS:.c=.o)
|
||||||
|
C_DEPS := $(C_SRCS:.c=.d)
|
||||||
|
|
||||||
|
DATABIN := $(TARGET:.elf=.bin)
|
||||||
|
|
||||||
|
$(DATABIN): $(TARGET)
|
||||||
|
$(OBJCOPY) $(BINFLAGS) $(TARGET) $@
|
||||||
|
|
||||||
|
$(TARGET): $(C_OBJS) patches.ld syms.ld
|
||||||
|
$(LD) $(LDFLAGS) $(C_OBJS) -o $@
|
||||||
|
|
||||||
|
$(C_OBJS): %.o : %.c
|
||||||
|
$(CC) $(CFLAGS) $(CPPFLAGS) $< -MMD -MF $(@:.o=.d) -c -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(C_OBJS) $(TARGET) $(DATABIN)
|
||||||
|
|
||||||
|
-include $(C_DEPS)
|
||||||
|
|
||||||
|
.PHONY: clean
|
139
patches/cheats.c
Normal file
139
patches/cheats.c
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#define Audio_PlaySfx play_sound
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
// Infinite magic
|
||||||
|
s32 Magic_Consume(PlayState* play, s16 magicToConsume, s16 type) {
|
||||||
|
InterfaceContext* interfaceCtx = &play->interfaceCtx;
|
||||||
|
|
||||||
|
magicToConsume = 0;
|
||||||
|
|
||||||
|
// // Magic is not acquired yet
|
||||||
|
// if (!gSaveContext.save.saveInfo.playerData.isMagicAcquired) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Not enough magic available to consume
|
||||||
|
if ((gSaveContext.save.saveInfo.playerData.magic - magicToConsume) < 0) {
|
||||||
|
if (gSaveContext.magicCapacity != 0) {
|
||||||
|
Audio_PlaySfx(NA_SE_SY_ERROR);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case MAGIC_CONSUME_NOW:
|
||||||
|
case MAGIC_CONSUME_NOW_ALT:
|
||||||
|
// Drain magic immediately e.g. Deku Bubble
|
||||||
|
if ((gSaveContext.magicState == MAGIC_STATE_IDLE) ||
|
||||||
|
(gSaveContext.magicState == MAGIC_STATE_CONSUME_LENS)) {
|
||||||
|
if (gSaveContext.magicState == MAGIC_STATE_CONSUME_LENS) {
|
||||||
|
play->actorCtx.lensActive = false;
|
||||||
|
}
|
||||||
|
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_DRANK_CHATEAU_ROMANI)) {
|
||||||
|
magicToConsume = 0;
|
||||||
|
}
|
||||||
|
gSaveContext.magicToConsume = magicToConsume;
|
||||||
|
gSaveContext.magicState = MAGIC_STATE_CONSUME_SETUP;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Audio_PlaySfx(NA_SE_SY_ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MAGIC_CONSUME_WAIT_NO_PREVIEW:
|
||||||
|
// Sets consume target but waits to consume.
|
||||||
|
// No yellow magic to preview target consumption.
|
||||||
|
if ((gSaveContext.magicState == MAGIC_STATE_IDLE) ||
|
||||||
|
(gSaveContext.magicState == MAGIC_STATE_CONSUME_LENS)) {
|
||||||
|
if (gSaveContext.magicState == MAGIC_STATE_CONSUME_LENS) {
|
||||||
|
play->actorCtx.lensActive = false;
|
||||||
|
}
|
||||||
|
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_DRANK_CHATEAU_ROMANI)) {
|
||||||
|
magicToConsume = 0;
|
||||||
|
}
|
||||||
|
gSaveContext.magicToConsume = magicToConsume;
|
||||||
|
gSaveContext.magicState = MAGIC_STATE_METER_FLASH_3;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Audio_PlaySfx(NA_SE_SY_ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MAGIC_CONSUME_LENS:
|
||||||
|
if (gSaveContext.magicState == MAGIC_STATE_IDLE) {
|
||||||
|
if (gSaveContext.save.saveInfo.playerData.magic != 0) {
|
||||||
|
interfaceCtx->magicConsumptionTimer = 80;
|
||||||
|
gSaveContext.magicState = MAGIC_STATE_CONSUME_LENS;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (gSaveContext.magicState == MAGIC_STATE_CONSUME_LENS) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MAGIC_CONSUME_WAIT_PREVIEW:
|
||||||
|
// Sets consume target but waits to consume.
|
||||||
|
// Preview consumption with a yellow bar. e.g. Spin Attack
|
||||||
|
if ((gSaveContext.magicState == MAGIC_STATE_IDLE) ||
|
||||||
|
(gSaveContext.magicState == MAGIC_STATE_CONSUME_LENS)) {
|
||||||
|
if (gSaveContext.magicState == MAGIC_STATE_CONSUME_LENS) {
|
||||||
|
play->actorCtx.lensActive = false;
|
||||||
|
}
|
||||||
|
gSaveContext.magicToConsume = magicToConsume;
|
||||||
|
gSaveContext.magicState = MAGIC_STATE_METER_FLASH_2;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Audio_PlaySfx(NA_SE_SY_ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MAGIC_CONSUME_GORON_ZORA:
|
||||||
|
// Goron spiked rolling or Zora electric barrier
|
||||||
|
if (gSaveContext.save.saveInfo.playerData.magic != 0) {
|
||||||
|
interfaceCtx->magicConsumptionTimer = 10;
|
||||||
|
gSaveContext.magicState = MAGIC_STATE_CONSUME_GORON_ZORA_SETUP;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MAGIC_CONSUME_GIANTS_MASK:
|
||||||
|
// Wearing Giant's Mask
|
||||||
|
if (gSaveContext.magicState == MAGIC_STATE_IDLE) {
|
||||||
|
if (gSaveContext.save.saveInfo.playerData.magic != 0) {
|
||||||
|
interfaceCtx->magicConsumptionTimer = R_MAGIC_CONSUME_TIMER_GIANTS_MASK;
|
||||||
|
gSaveContext.magicState = MAGIC_STATE_CONSUME_GIANTS_MASK;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gSaveContext.magicState == MAGIC_STATE_CONSUME_GIANTS_MASK) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MAGIC_CONSUME_DEITY_BEAM:
|
||||||
|
// Consumes magic immediately
|
||||||
|
if ((gSaveContext.magicState == MAGIC_STATE_IDLE) ||
|
||||||
|
(gSaveContext.magicState == MAGIC_STATE_CONSUME_LENS)) {
|
||||||
|
if (gSaveContext.magicState == MAGIC_STATE_CONSUME_LENS) {
|
||||||
|
play->actorCtx.lensActive = false;
|
||||||
|
}
|
||||||
|
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_DRANK_CHATEAU_ROMANI)) {
|
||||||
|
magicToConsume = 0;
|
||||||
|
}
|
||||||
|
gSaveContext.save.saveInfo.playerData.magic -= magicToConsume;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Audio_PlaySfx(NA_SE_SY_ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
47
patches/culling.c
Normal file
47
patches/culling.c
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
// Disable frustum culling for actors, but leave distance culling intact
|
||||||
|
s32 func_800BA2FC(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projectedW) {
|
||||||
|
if ((-actor->uncullZoneScale < projectedPos->z) &&
|
||||||
|
(projectedPos->z < (actor->uncullZoneForward + actor->uncullZoneScale))) {
|
||||||
|
// f32 phi_f12;
|
||||||
|
// f32 phi_f2 = CLAMP_MIN(projectedW, 1.0f);
|
||||||
|
// f32 phi_f14;
|
||||||
|
// f32 phi_f16;
|
||||||
|
|
||||||
|
// if (play->view.fovy != 60.0f) {
|
||||||
|
// phi_f12 = actor->uncullZoneScale * play->projectionMtxFDiagonal.x * 0.76980036f; // sqrt(16/27)
|
||||||
|
|
||||||
|
// phi_f14 = play->projectionMtxFDiagonal.y * 0.57735026f; // 1 / sqrt(3)
|
||||||
|
// phi_f16 = actor->uncullZoneScale * phi_f14;
|
||||||
|
// phi_f14 *= actor->uncullZoneDownward;
|
||||||
|
// } else {
|
||||||
|
// phi_f16 = phi_f12 = actor->uncullZoneScale;
|
||||||
|
// phi_f14 = actor->uncullZoneDownward;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (((fabsf(projectedPos->x) - phi_f12) < phi_f2) && ((-phi_f2 < (projectedPos->y + phi_f14))) &&
|
||||||
|
// ((projectedPos->y - phi_f16) < phi_f2)) {
|
||||||
|
return true;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override LOD to 0
|
||||||
|
void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gfx* cullDList,
|
||||||
|
OverrideLimbDrawFlex overrideLimbDraw) {
|
||||||
|
OPEN_DISPS(play->state.gfxCtx);
|
||||||
|
|
||||||
|
gSPSegment(POLY_OPA_DISP++, 0x0C, cullDList);
|
||||||
|
gSPSegment(POLY_XLU_DISP++, 0x0C, cullDList);
|
||||||
|
|
||||||
|
lod = 0; // Force the closest LOD
|
||||||
|
|
||||||
|
Player_DrawImpl(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, lod,
|
||||||
|
this->transformation, 0, this->actor.shape.face, overrideLimbDraw, Player_PostLimbDrawGameplay,
|
||||||
|
&this->actor);
|
||||||
|
|
||||||
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
|
}
|
21
patches/patches.ld
Normal file
21
patches/patches.ld
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
RAMBASE = 0x80800100; /* Used to hold any new symbols */
|
||||||
|
|
||||||
|
MEMORY {
|
||||||
|
extram : ORIGIN = RAMBASE, LENGTH = 1M
|
||||||
|
rom : ORIGIN = 0, LENGTH = 1M
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
.text : { *(.text*) } >extram AT >rom
|
||||||
|
.ctors : { *(.ctors*) *(.init_array*) } >extram AT >rom
|
||||||
|
.dtors : { *(.dtors*) } >extram AT >rom
|
||||||
|
.rodata : { *(.rodata*) } >extram AT >rom
|
||||||
|
.data : { *(.data*) } >extram AT >rom
|
||||||
|
.bss (NOLOAD) : { *(.bss*) *(COMMON) } >extram
|
||||||
|
|
||||||
|
.symtab 0 : { *(.symtab) }
|
||||||
|
.strtab 0 : { *(.strtab) }
|
||||||
|
.shstrtab 0 : { *(.shstrtab) }
|
||||||
|
|
||||||
|
/DISCARD/ : { *(*); }
|
||||||
|
}
|
7
patches/syms.ld
Normal file
7
patches/syms.ld
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
__start = 0x80000000;
|
||||||
|
/* TODO pull these symbols from the elf file directly */
|
||||||
|
Player_PostLimbDrawGameplay = 0x80128BD0;
|
||||||
|
Player_DrawImpl = 0x801246F4;
|
||||||
|
gRegEditor = 0x801f3f60;
|
||||||
|
play_sound = 0x8019f0c8;
|
||||||
|
gSaveContext = 0x801ef670;
|
@ -148,6 +148,7 @@ int sdl_event_filter(void* userdata, SDL_Event* event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Multilibultra::gfx_callbacks_t::gfx_data_t create_gfx() {
|
Multilibultra::gfx_callbacks_t::gfx_data_t create_gfx() {
|
||||||
|
SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "system");
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) > 0) {
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) > 0) {
|
||||||
exit_error("Failed to initialize SDL2: %s\n", SDL_GetError());
|
exit_error("Failed to initialize SDL2: %s\n", SDL_GetError());
|
||||||
}
|
}
|
||||||
@ -158,7 +159,7 @@ Multilibultra::gfx_callbacks_t::gfx_data_t create_gfx() {
|
|||||||
SDL_Window* window;
|
SDL_Window* window;
|
||||||
|
|
||||||
Multilibultra::WindowHandle create_window(Multilibultra::gfx_callbacks_t::gfx_data_t) {
|
Multilibultra::WindowHandle create_window(Multilibultra::gfx_callbacks_t::gfx_data_t) {
|
||||||
window = SDL_CreateWindow("Recomp", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_RESIZABLE);
|
window = SDL_CreateWindow("Recomp", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_RESIZABLE );
|
||||||
|
|
||||||
if (window == nullptr) {
|
if (window == nullptr) {
|
||||||
exit_error("Failed to create window: %s\n", SDL_GetError());
|
exit_error("Failed to create window: %s\n", SDL_GetError());
|
||||||
|
48
src/ui/ui_events.cpp
Normal file
48
src/ui/ui_events.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "recomp_ui.h"
|
||||||
|
#include "../../portultra/multilibultra.hpp"
|
||||||
|
|
||||||
|
#include "nfd.h"
|
||||||
|
#include "RmlUi/Core.h"
|
||||||
|
|
||||||
|
using event_handler_t = void(Rml::Event&);
|
||||||
|
|
||||||
|
class UiEventListener : public Rml::EventListener {
|
||||||
|
event_handler_t* handler_;
|
||||||
|
public:
|
||||||
|
UiEventListener(event_handler_t* handler) : handler_(handler) {}
|
||||||
|
void ProcessEvent(Rml::Event& event) override {
|
||||||
|
handler_(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class UiEventListenerInstancer : public Rml::EventListenerInstancer {
|
||||||
|
std::unordered_map<Rml::String, UiEventListener> listener_map_;
|
||||||
|
public:
|
||||||
|
Rml::EventListener* InstanceEventListener(const Rml::String& value, Rml::Element* element) override {
|
||||||
|
printf("Instancing event listener for %s\n", value.c_str());
|
||||||
|
auto find_it = listener_map_.find(value);
|
||||||
|
|
||||||
|
if (find_it != listener_map_.end()) {
|
||||||
|
return &find_it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_event(const Rml::String& value, event_handler_t* handler) {
|
||||||
|
listener_map_.emplace(value, UiEventListener{ handler });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Rml::EventListenerInstancer> make_event_listener_instancer() {
|
||||||
|
std::unique_ptr<UiEventListenerInstancer> ret = std::make_unique<UiEventListenerInstancer>();
|
||||||
|
|
||||||
|
ret->register_event("start_game",
|
||||||
|
[](Rml::Event& event) {
|
||||||
|
Multilibultra::start_game(0);
|
||||||
|
set_current_menu(Menu::None);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
@ -5,6 +5,8 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "recomp_ui.h"
|
||||||
|
|
||||||
#include "concurrentqueue.h"
|
#include "concurrentqueue.h"
|
||||||
|
|
||||||
#include "rt64_layer.h"
|
#include "rt64_layer.h"
|
||||||
@ -124,7 +126,7 @@ class RmlRenderInterface_RT64 : public Rml::RenderInterface {
|
|||||||
Rml::Matrix4f transform_ = Rml::Matrix4f::Identity();
|
Rml::Matrix4f transform_ = Rml::Matrix4f::Identity();
|
||||||
Rml::Matrix4f mvp_ = Rml::Matrix4f::Identity();
|
Rml::Matrix4f mvp_ = Rml::Matrix4f::Identity();
|
||||||
std::unordered_map<Rml::TextureHandle, TextureHandle> textures_{};
|
std::unordered_map<Rml::TextureHandle, TextureHandle> textures_{};
|
||||||
Rml::TextureHandle texture_count_ = 0;
|
Rml::TextureHandle texture_count_ = 1; // Start at 1 to reserve texture 0 as the 1x1 pixel white texture
|
||||||
std::unique_ptr<RT64::RenderBuffer> upload_buffer_{};
|
std::unique_ptr<RT64::RenderBuffer> upload_buffer_{};
|
||||||
std::unique_ptr<RT64::RenderBuffer> vertex_buffer_{};
|
std::unique_ptr<RT64::RenderBuffer> vertex_buffer_{};
|
||||||
std::unique_ptr<RT64::RenderBuffer> index_buffer_{};
|
std::unique_ptr<RT64::RenderBuffer> index_buffer_{};
|
||||||
@ -251,8 +253,22 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t allocate_upload_data_aligned(uint32_t num_bytes, uint32_t alignment) {
|
uint32_t allocate_upload_data_aligned(uint32_t num_bytes, uint32_t alignment) {
|
||||||
|
// Check if there's enough remaining room in the upload buffer to allocate the requested bytes.
|
||||||
|
uint32_t total_bytes = num_bytes + upload_buffer_bytes_used_;
|
||||||
|
|
||||||
|
// Determine the amount of padding needed to meet the target alignment.
|
||||||
uint32_t padding_bytes = ((upload_buffer_bytes_used_ + alignment - 1) / alignment) * alignment - upload_buffer_bytes_used_;
|
uint32_t padding_bytes = ((upload_buffer_bytes_used_ + alignment - 1) / alignment) * alignment - upload_buffer_bytes_used_;
|
||||||
|
|
||||||
|
// If there isn't enough room to allocate the required bytes plus the padding then resize the upload buffer and allocate from the start of the new one.
|
||||||
|
if (total_bytes + padding_bytes > upload_buffer_size_) {
|
||||||
|
resize_upload_buffer(total_bytes + total_bytes / 2);
|
||||||
|
|
||||||
|
upload_buffer_bytes_used_ += num_bytes;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise allocate the padding and required bytes and offset the allocated position by the padding size.
|
||||||
return allocate_upload_data(padding_bytes + num_bytes) + padding_bytes;
|
return allocate_upload_data(padding_bytes + num_bytes) + padding_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,8 +389,6 @@ public:
|
|||||||
std::filesystem::path image_path{ source.c_str() };
|
std::filesystem::path image_path{ source.c_str() };
|
||||||
|
|
||||||
if (image_path.extension() == ".tga") {
|
if (image_path.extension() == ".tga") {
|
||||||
printf("Opening TGA image: %s\n", image_path.u8string().c_str());
|
|
||||||
|
|
||||||
std::vector<char> file_data = read_file(image_path);
|
std::vector<char> file_data = read_file(image_path);
|
||||||
|
|
||||||
if (file_data.empty()) {
|
if (file_data.empty()) {
|
||||||
@ -531,7 +545,7 @@ public:
|
|||||||
mvp_ = projection_mtx_ * transform_;
|
mvp_ = projection_mtx_ * transform_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void start(RT64::RenderCommandList* list, uint32_t image_width, uint32_t image_height, bool reload_style) {
|
void start(RT64::RenderCommandList* list, uint32_t image_width, uint32_t image_height) {
|
||||||
list_ = list;
|
list_ = list;
|
||||||
list_->setPipeline(pipeline_.get());
|
list_->setPipeline(pipeline_.get());
|
||||||
list_->setGraphicsPipelineLayout(layout_.get());
|
list_->setGraphicsPipelineLayout(layout_.get());
|
||||||
@ -546,10 +560,6 @@ public:
|
|||||||
// Clear out any stale buffers from the last command list.
|
// Clear out any stale buffers from the last command list.
|
||||||
stale_buffers_.clear();
|
stale_buffers_.clear();
|
||||||
|
|
||||||
if (reload_style) {
|
|
||||||
load_document();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset and map the upload buffer.
|
// Reset and map the upload buffer.
|
||||||
upload_buffer_bytes_used_ = 0;
|
upload_buffer_bytes_used_ = 0;
|
||||||
upload_buffer_mapped_data_ = reinterpret_cast<uint8_t*>(upload_buffer_->map());
|
upload_buffer_mapped_data_ = reinterpret_cast<uint8_t*>(upload_buffer_->map());
|
||||||
@ -568,32 +578,60 @@ public:
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct UIRenderContext render;
|
struct UIRenderContext render;
|
||||||
struct {
|
class {
|
||||||
|
std::unordered_map<Menu, Rml::ElementDocument*> documents;
|
||||||
|
Rml::ElementDocument* current_document;
|
||||||
|
public:
|
||||||
SystemInterface_SDL system_interface;
|
SystemInterface_SDL system_interface;
|
||||||
std::unique_ptr<RmlRenderInterface_RT64> render_interface;
|
std::unique_ptr<RmlRenderInterface_RT64> render_interface;
|
||||||
Rml::Context* context;
|
Rml::Context* context;
|
||||||
|
std::unique_ptr<Rml::EventListenerInstancer> event_listener_instancer;
|
||||||
|
|
||||||
|
void swap_document(Menu menu) {
|
||||||
|
if (current_document != nullptr) {
|
||||||
|
current_document->Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto find_it = documents.find(menu);
|
||||||
|
if (find_it != documents.end()) {
|
||||||
|
assert(find_it->second && "Document for menu not loaded!");
|
||||||
|
current_document = find_it->second;
|
||||||
|
current_document->Show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
current_document = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_documents() {
|
||||||
|
if (!documents.empty()) {
|
||||||
|
Rml::Factory::RegisterEventListenerInstancer(nullptr);
|
||||||
|
for (auto doc : documents) {
|
||||||
|
doc.second->ReloadStyleSheet();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::ReleaseTextures();
|
||||||
|
Rml::ReleaseMemoryPools();
|
||||||
|
|
||||||
|
if (current_document != nullptr) {
|
||||||
|
current_document->Hide();
|
||||||
|
current_document->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
current_document = nullptr;
|
||||||
|
|
||||||
|
documents.clear();
|
||||||
|
Rml::Factory::RegisterEventListenerInstancer(event_listener_instancer.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
documents.emplace(Menu::Launcher, context->LoadDocument("assets/launcher.rml"));
|
||||||
|
}
|
||||||
} rml;
|
} rml;
|
||||||
} UIContext;
|
} UIContext;
|
||||||
|
|
||||||
// TODO make this not be global
|
// TODO make this not be global
|
||||||
extern SDL_Window* window;
|
extern SDL_Window* window;
|
||||||
|
|
||||||
void load_document() {
|
|
||||||
if (UIContext.render.document) {
|
|
||||||
UIContext.render.document->ReloadStyleSheet();
|
|
||||||
Rml::ReleaseTextures();
|
|
||||||
Rml::ReleaseMemoryPools();
|
|
||||||
UIContext.render.document->Hide();
|
|
||||||
UIContext.render.document->Close();
|
|
||||||
// Documents are owned by RmlUi, so we don't have anything to free here.
|
|
||||||
UIContext.render.document = nullptr;
|
|
||||||
}
|
|
||||||
UIContext.render.document = UIContext.rml.context->LoadDocument("assets/demo.rml");
|
|
||||||
if (UIContext.render.document) {
|
|
||||||
UIContext.render.document->Show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
||||||
printf("RT64 hook init\n");
|
printf("RT64 hook init\n");
|
||||||
|
|
||||||
@ -603,9 +641,11 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
|||||||
// Setup RML
|
// Setup RML
|
||||||
UIContext.rml.system_interface.SetWindow(window);
|
UIContext.rml.system_interface.SetWindow(window);
|
||||||
UIContext.rml.render_interface = std::make_unique<RmlRenderInterface_RT64>(&UIContext.render);
|
UIContext.rml.render_interface = std::make_unique<RmlRenderInterface_RT64>(&UIContext.render);
|
||||||
|
UIContext.rml.event_listener_instancer = make_event_listener_instancer();
|
||||||
|
|
||||||
Rml::SetSystemInterface(&UIContext.rml.system_interface);
|
Rml::SetSystemInterface(&UIContext.rml.system_interface);
|
||||||
Rml::SetRenderInterface(UIContext.rml.render_interface.get());
|
Rml::SetRenderInterface(UIContext.rml.render_interface.get());
|
||||||
|
Rml::Factory::RegisterEventListenerInstancer(UIContext.rml.event_listener_instancer.get());
|
||||||
|
|
||||||
Rml::Initialise();
|
Rml::Initialise();
|
||||||
|
|
||||||
@ -636,7 +676,7 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
load_document();
|
UIContext.rml.load_documents();
|
||||||
}
|
}
|
||||||
|
|
||||||
moodycamel::ConcurrentQueue<SDL_Event> ui_event_queue{};
|
moodycamel::ConcurrentQueue<SDL_Event> ui_event_queue{};
|
||||||
@ -649,6 +689,8 @@ bool try_deque_event(SDL_Event& out) {
|
|||||||
return ui_event_queue.try_dequeue(out);
|
return ui_event_queue.try_dequeue(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::atomic<Menu> open_menu = Menu::Launcher;
|
||||||
|
|
||||||
void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_chain_texture) {
|
void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_chain_texture) {
|
||||||
int num_keys;
|
int num_keys;
|
||||||
const Uint8* key_state = SDL_GetKeyboardState(&num_keys);
|
const Uint8* key_state = SDL_GetKeyboardState(&num_keys);
|
||||||
@ -658,20 +700,19 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_
|
|||||||
bool reload_sheets = is_reload_held && !was_reload_held;
|
bool reload_sheets = is_reload_held && !was_reload_held;
|
||||||
was_reload_held = is_reload_held;
|
was_reload_held = is_reload_held;
|
||||||
|
|
||||||
static bool menu_open = true;
|
static Menu prev_menu = Menu::None;
|
||||||
static bool was_toggle_menu_held = false;
|
Menu cur_menu = open_menu.load();
|
||||||
bool is_toggle_menu_held = key_state[SDL_SCANCODE_M] != 0;
|
|
||||||
if (is_toggle_menu_held && !was_toggle_menu_held) {
|
|
||||||
menu_open = !menu_open;
|
|
||||||
}
|
|
||||||
was_toggle_menu_held = is_toggle_menu_held;
|
|
||||||
|
|
||||||
static bool was_start_game_held = false;
|
if (reload_sheets) {
|
||||||
bool is_start_game_held = key_state[SDL_SCANCODE_SPACE] != 0;
|
UIContext.rml.load_documents();
|
||||||
if (is_start_game_held && !was_start_game_held) {
|
prev_menu = Menu::None;
|
||||||
Multilibultra::start_game(0);
|
|
||||||
}
|
}
|
||||||
was_start_game_held = is_start_game_held;
|
|
||||||
|
if (cur_menu != prev_menu) {
|
||||||
|
UIContext.rml.swap_document(cur_menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_menu = cur_menu;
|
||||||
|
|
||||||
SDL_Event cur_event{};
|
SDL_Event cur_event{};
|
||||||
|
|
||||||
@ -679,11 +720,11 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_
|
|||||||
RmlSDL::InputEventHandler(UIContext.rml.context, cur_event);
|
RmlSDL::InputEventHandler(UIContext.rml.context, cur_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (menu_open) {
|
if (cur_menu != Menu::None) {
|
||||||
int width, height;
|
int width, height;
|
||||||
SDL_GetWindowSizeInPixels(window, &width, &height);
|
SDL_GetWindowSizeInPixels(window, &width, &height);
|
||||||
|
|
||||||
UIContext.rml.render_interface->start(command_list, width, height, reload_sheets);
|
UIContext.rml.render_interface->start(command_list, width, height);
|
||||||
|
|
||||||
static int prev_width = 0;
|
static int prev_width = 0;
|
||||||
static int prev_height = 0;
|
static int prev_height = 0;
|
||||||
@ -707,3 +748,7 @@ void deinit_hook() {
|
|||||||
void set_rt64_hooks() {
|
void set_rt64_hooks() {
|
||||||
RT64::SetRenderHooks(init_hook, draw_hook, deinit_hook);
|
RT64::SetRenderHooks(init_hook, draw_hook, deinit_hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_current_menu(Menu menu) {
|
||||||
|
open_menu.store(menu);
|
||||||
|
}
|
1
thirdparty/nativefiledialog-extended
vendored
Submodule
1
thirdparty/nativefiledialog-extended
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 75cbdf819785d9f94855987724e30a6ba0a87e29
|
Loading…
Reference in New Issue
Block a user