Compare commits
21 Commits
5ecdc93f8e
...
65083d2863
Author | SHA1 | Date |
---|---|---|
dcvz | 65083d2863 | |
Mr-Wiseguy | b9ea76847f | |
LittleCube | 7bcb984347 | |
Mr-Wiseguy | 4767424aee | |
Mr-Wiseguy | beeef1c7ef | |
Mr-Wiseguy | 26607e541f | |
Mr-Wiseguy | 806d9bc848 | |
Mr-Wiseguy | 1e792299c8 | |
Mr-Wiseguy | 64793ef337 | |
Mr-Wiseguy | 49517ff978 | |
Mr-Wiseguy | 9b6296871b | |
Mr-Wiseguy | 50536858c8 | |
Mr-Wiseguy | 99dc216c75 | |
Mr-Wiseguy | c2d7a47512 | |
Mr-Wiseguy | 25e6ca6717 | |
Mr-Wiseguy | cffda249a7 | |
Mr-Wiseguy | f4e8884de6 | |
Mr-Wiseguy | a9bb035c0b | |
Mr-Wiseguy | 5a8de31e82 | |
Mr-Wiseguy | d4a8cd351e | |
Mr-Wiseguy | d68a8063c4 |
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>Zelda64Recompiled</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||||
|
<key>LSApplicationCategoryType</key>
|
||||||
|
<string>public.app-category.games</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>11</string>
|
||||||
|
<key>LSEnvironment</key>
|
||||||
|
<dict>
|
||||||
|
<key>MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>MVK_CONFIG_USE_METAL_PRIVATE_API</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>MVK_CONFIG_RESUME_LOST_DEVICE</key>
|
||||||
|
<string>1</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"file_format_version": "1.0.0",
|
||||||
|
"ICD": {
|
||||||
|
"library_path": "../../../Frameworks/libMoltenVK.dylib",
|
||||||
|
"api_version": "1.2.0",
|
||||||
|
"is_portability_driver": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
include(BundleUtilities)
|
||||||
|
|
||||||
|
# Use generator expressions to get the absolute path to the bundle and frameworks
|
||||||
|
set(APPS "Zelda64Recompiled.app/Contents/MacOS/Zelda64Recompiled")
|
||||||
|
set(DIRS "Zelda64Recompiled.app/Contents/Frameworks")
|
||||||
|
|
||||||
|
# The fixup_bundle command needs an absolute path
|
||||||
|
file(REAL_PATH ${APPS} APPS)
|
||||||
|
file(REAL_PATH ${DIRS} DIRS)
|
||||||
|
|
||||||
|
fixup_bundle("${APPS}" "" "${DIRS}")
|
|
@ -0,0 +1,14 @@
|
||||||
|
version: '2.9.3'
|
||||||
|
prefix: '/opt/local'
|
||||||
|
variants:
|
||||||
|
select:
|
||||||
|
- aqua
|
||||||
|
- metal
|
||||||
|
deselect: x11
|
||||||
|
ports:
|
||||||
|
- name: clang-18
|
||||||
|
- name: llvm-18
|
||||||
|
- name: libsdl2
|
||||||
|
select: universal
|
||||||
|
- name: freetype
|
||||||
|
select: universal
|
|
@ -9,11 +9,19 @@ on:
|
||||||
N64RECOMP_COMMIT:
|
N64RECOMP_COMMIT:
|
||||||
type: string
|
type: string
|
||||||
required: false
|
required: false
|
||||||
default: 'f8d439aeee6048b7365d1cb3bcd2578ec27a0288'
|
default: 'd33d38161798167929b114c2b0fd445f9670e10a'
|
||||||
DXC_CHECKSUM:
|
DXC_CHECKSUM:
|
||||||
type: string
|
type: string
|
||||||
required: false
|
required: false
|
||||||
default: '4e6f4e52989aca69739880b40b9f988357f15d10ca03284377b81f1502463ff5'
|
default: '4e6f4e52989aca69739880b40b9f988357f15d10ca03284377b81f1502463ff5'
|
||||||
|
VULKAN_SDK_VERSION:
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
default: '1.3.290.0'
|
||||||
|
MOLTENVK_COMMIT:
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
default: '3b9e335fe8fc8a72cf6099acbd54128889445c0a'
|
||||||
secrets:
|
secrets:
|
||||||
ZRE_REPO_WITH_PAT:
|
ZRE_REPO_WITH_PAT:
|
||||||
required: true
|
required: true
|
||||||
|
@ -64,7 +72,7 @@ jobs:
|
||||||
|
|
||||||
# Build N64Recomp & RSPRecomp
|
# Build N64Recomp & RSPRecomp
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build
|
||||||
cmake --build cmake-build --config Release --target N64Recomp -j $(nproc)
|
cmake --build cmake-build --config Release --target N64RecompCLI -j $(nproc)
|
||||||
cmake --build cmake-build --config Release --target RSPRecomp -j $(nproc)
|
cmake --build cmake-build --config Release --target RSPRecomp -j $(nproc)
|
||||||
|
|
||||||
# Copy N64Recomp & RSPRecomp to root directory
|
# Copy N64Recomp & RSPRecomp to root directory
|
||||||
|
@ -95,7 +103,7 @@ jobs:
|
||||||
rm -rf assets/scss
|
rm -rf assets/scss
|
||||||
tar -czf Zelda64Recompiled.tar.gz Zelda64Recompiled assets/ gamecontrollerdb.txt
|
tar -czf Zelda64Recompiled.tar.gz Zelda64Recompiled assets/ gamecontrollerdb.txt
|
||||||
- name: Archive Zelda64Recomp
|
- name: Archive Zelda64Recomp
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Zelda64Recompiled-${{ runner.os }}-X64-${{ matrix.type }}
|
name: Zelda64Recompiled-${{ runner.os }}-X64-${{ matrix.type }}
|
||||||
path: Zelda64Recompiled.tar.gz
|
path: Zelda64Recompiled.tar.gz
|
||||||
|
@ -103,7 +111,7 @@ jobs:
|
||||||
run: |-
|
run: |-
|
||||||
./.github/linux/appimage.sh
|
./.github/linux/appimage.sh
|
||||||
- name: Zelda64Recomp AppImage
|
- name: Zelda64Recomp AppImage
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Zelda64Recompiled-AppImage-X64-${{ matrix.type }}
|
name: Zelda64Recompiled-AppImage-X64-${{ matrix.type }}
|
||||||
path: Zelda64Recompiled-*.AppImage
|
path: Zelda64Recompiled-*.AppImage
|
||||||
|
@ -160,7 +168,7 @@ jobs:
|
||||||
|
|
||||||
# Build N64Recomp & RSPRecomp
|
# Build N64Recomp & RSPRecomp
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build
|
||||||
cmake --build cmake-build --config Release --target N64Recomp -j $(nproc)
|
cmake --build cmake-build --config Release --target N64RecompCLI -j $(nproc)
|
||||||
cmake --build cmake-build --config Release --target RSPRecomp -j $(nproc)
|
cmake --build cmake-build --config Release --target RSPRecomp -j $(nproc)
|
||||||
|
|
||||||
# Copy N64Recomp & RSPRecomp to root directory
|
# Copy N64Recomp & RSPRecomp to root directory
|
||||||
|
@ -234,7 +242,7 @@ jobs:
|
||||||
$cpuCores = (Get-CimInstance -ClassName Win32_Processor).NumberOfLogicalProcessors
|
$cpuCores = (Get-CimInstance -ClassName Win32_Processor).NumberOfLogicalProcessors
|
||||||
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build
|
||||||
cmake --build cmake-build --config Release --target N64Recomp -j $cpuCores
|
cmake --build cmake-build --config Release --target N64RecompCLI -j $cpuCores
|
||||||
cmake --build cmake-build --config Release --target RSPRecomp -j $cpuCores
|
cmake --build cmake-build --config Release --target RSPRecomp -j $cpuCores
|
||||||
|
|
||||||
# Copy N64Recomp & RSPRecomp to root directory
|
# Copy N64Recomp & RSPRecomp to root directory
|
||||||
|
@ -276,3 +284,117 @@ jobs:
|
||||||
SDL2.dll
|
SDL2.dll
|
||||||
assets/
|
assets/
|
||||||
gamecontrollerdb.txt
|
gamecontrollerdb.txt
|
||||||
|
build-macos:
|
||||||
|
runs-on: blaze/macos-14
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
type: [ Debug, Release ]
|
||||||
|
name: macos (x64, arm64, ${{ matrix.type }})
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.ref }}
|
||||||
|
submodules: recursive
|
||||||
|
- name: ccache
|
||||||
|
uses: hendrikmuhs/ccache-action@v1.2
|
||||||
|
with:
|
||||||
|
key: ${{ runner.os }}-z64re-ccache-${{ matrix.type }}
|
||||||
|
- name: Homebrew Setup
|
||||||
|
run: |
|
||||||
|
brew install ninja
|
||||||
|
brew uninstall --ignore-dependencies libpng freetype
|
||||||
|
- name: MacPorts Setup
|
||||||
|
uses: melusina-org/setup-macports@v1
|
||||||
|
id: 'macports'
|
||||||
|
with:
|
||||||
|
parameters: '.github/macos/macports.yaml'
|
||||||
|
- name: Prepare Build
|
||||||
|
run: |-
|
||||||
|
git clone ${{ secrets.ZRE_REPO_WITH_PAT }}
|
||||||
|
./zre/process.sh
|
||||||
|
cp ./zre/mm_shader_cache.bin ./shadercache/
|
||||||
|
- name: Build N64Recomp & RSPRecomp
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/Mr-Wiseguy/N64Recomp.git --recurse-submodules N64RecompSource
|
||||||
|
cd N64RecompSource
|
||||||
|
git checkout ${{ inputs.N64RECOMP_COMMIT }}
|
||||||
|
git submodule update --init --recursive
|
||||||
|
|
||||||
|
# enable ccache
|
||||||
|
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||||
|
|
||||||
|
# Build N64Recomp & RSPRecomp
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build
|
||||||
|
cmake --build cmake-build --config Release --target N64Recomp -j $(sysctl -n hw.ncpu)
|
||||||
|
cmake --build cmake-build --config Release --target RSPRecomp -j $(sysctl -n hw.ncpu)
|
||||||
|
|
||||||
|
# Copy N64Recomp & RSPRecomp to root directory
|
||||||
|
cp cmake-build/N64Recomp ..
|
||||||
|
cp cmake-build/RSPRecomp ..
|
||||||
|
- name: Run N64Recomp & RSPRecomp
|
||||||
|
run: |
|
||||||
|
./N64Recomp us.rev1.toml
|
||||||
|
./RSPRecomp aspMain.us.rev1.toml
|
||||||
|
./RSPRecomp njpgdspMain.us.rev1.toml
|
||||||
|
- name: Cache Vulkan SDK
|
||||||
|
id: cache-vulkan-sdk
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: /Users/runner/VulkanSDK/${{ inputs.VULKAN_SDK_VERSION }}
|
||||||
|
key: ${{ runner.os }}-${{ matrix.type }}-vulkan-sdk-${{ inputs.VULKAN_SDK_VERSION }}
|
||||||
|
- name: Install Vulkan SDK
|
||||||
|
if: steps.cache-vulkan-sdk.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
wget https://sdk.lunarg.com/sdk/download/${{ inputs.VULKAN_SDK_VERSION }}/mac/vulkansdk-macos-${{ inputs.VULKAN_SDK_VERSION }}.dmg
|
||||||
|
hdiutil attach ./vulkansdk-macos-${{ inputs.VULKAN_SDK_VERSION }}.dmg
|
||||||
|
sudo /Volumes/vulkansdk-macos-${{ inputs.VULKAN_SDK_VERSION }}/InstallVulkan.app/Contents/MacOS/InstallVulkan --root ~/VulkanSDK/${{ inputs.VULKAN_SDK_VERSION }} --accept-licenses --default-answer --confirm-command install
|
||||||
|
hdiutil detach /Volumes/vulkansdk-macos-${{ inputs.VULKAN_SDK_VERSION }}
|
||||||
|
- name: Checkout MoltenVK
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/KhronosGroup/MoltenVK.git
|
||||||
|
cd MoltenVK
|
||||||
|
git checkout ${{ inputs.MOLTENVK_COMMIT }}
|
||||||
|
- name: Cache MoltenVK Dependencies
|
||||||
|
id: cache-mvk-dependencies
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
MoltenVK/External/build
|
||||||
|
!MoltenVK/External/build/Intermediates
|
||||||
|
key: ${{ runner.os }}-${{ matrix.type }}-${{ hashFiles('MoltenVK/fetchDependencies','MoltenVK/ExternalRevisions/**','MoltenVK/ExternalDependencies.xcodeproj/**','MoltenVK/Scripts/**') }}
|
||||||
|
- name: Fetch MVK Dependencies (Use Built Cache)
|
||||||
|
if: steps.cache-mvk-dependencies.outputs.cache-hit == 'true'
|
||||||
|
run: |
|
||||||
|
cd MoltenVK
|
||||||
|
./fetchDependencies -v --none
|
||||||
|
- name: Fetch MVK Dependencies
|
||||||
|
if: steps.cache-mvk-dependencies.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
cd MoltenVK
|
||||||
|
./fetchDependencies -v --macos
|
||||||
|
- name: Build MoltenVK
|
||||||
|
run: |
|
||||||
|
cd MoltenVK
|
||||||
|
make macos
|
||||||
|
sudo cp Package/Latest/MoltenVK/dylib/macOS/libMoltenVK.dylib ~/VulkanSDK/${{ inputs.VULKAN_SDK_VERSION }}/macOS/lib/libMoltenVK.dylib
|
||||||
|
- name: Build ZeldaRecomp
|
||||||
|
run: |-
|
||||||
|
# enable ccache
|
||||||
|
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||||
|
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build \
|
||||||
|
-DPATCHES_LD=/opt/local/bin/ld.lld-mp-18 -DPATCHES_OBJCOPY=/opt/local/bin/llvm-objcopy-mp-18 -DCMAKE_AR=/opt/local/bin/llvm-ar-mp-18 -DPATCHES_C_COMPILER=/opt/local/bin/clang-mp-18 \
|
||||||
|
-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
|
||||||
|
cmake --build cmake-build --config ${{ matrix.type }} --target Zelda64Recompiled -j $(sysctl -n hw.ncpu)
|
||||||
|
env:
|
||||||
|
VULKAN_SDK: /Users/runner/VulkanSDK/${{ inputs.VULKAN_SDK_VERSION }}/macOS
|
||||||
|
- name: Prepare Archive
|
||||||
|
run: |
|
||||||
|
mv cmake-build/Zelda64Recompiled.app Zelda64Recompiled.app
|
||||||
|
zip -r -y Zelda64Recompiled.zip Zelda64Recompiled.app
|
||||||
|
- name: Archive Zelda64Recomp
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Zelda64Recompiled-${{ runner.os }}-${{ matrix.type }}
|
||||||
|
path: Zelda64Recompiled.zip
|
||||||
|
|
161
CMakeLists.txt
161
CMakeLists.txt
|
@ -1,5 +1,10 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
project(Zelda64Recompiled)
|
|
||||||
|
if (APPLE) # has to be set before the first project() or enable_language()
|
||||||
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum OS X deployment version")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
project(Zelda64Recompiled LANGUAGES C CXX)
|
||||||
set(CMAKE_C_STANDARD 17)
|
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)
|
||||||
|
@ -15,6 +20,30 @@ if (WIN32)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
enable_language(OBJC OBJCXX)
|
||||||
|
|
||||||
|
# Check if VULKAN_SDK environment variable is set
|
||||||
|
if(NOT DEFINED ENV{VULKAN_SDK})
|
||||||
|
message(FATAL_ERROR "VULKAN_SDK environment variable is not set.")
|
||||||
|
else()
|
||||||
|
set(VULKAN_SDK $ENV{VULKAN_SDK})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Define paths to Vulkan loader and MoltenVK libraries
|
||||||
|
set(VULKAN_LOADER_PATH "${VULKAN_SDK}/lib/libvulkan.dylib")
|
||||||
|
set(MOLTENVK_PATH "${VULKAN_SDK}/lib/libMoltenVK.dylib")
|
||||||
|
|
||||||
|
# Ensure the Vulkan loader and MoltenVK libraries exist
|
||||||
|
if(NOT EXISTS "${VULKAN_LOADER_PATH}")
|
||||||
|
message(FATAL_ERROR "Vulkan loader not found at ${VULKAN_LOADER_PATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${MOLTENVK_PATH}")
|
||||||
|
message(FATAL_ERROR "MoltenVK not found at ${MOLTENVK_PATH}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24:
|
# Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24:
|
||||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
|
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
|
||||||
cmake_policy(SET CMP0135 NEW)
|
cmake_policy(SET CMP0135 NEW)
|
||||||
|
@ -135,21 +164,12 @@ add_custom_target(DownloadGameControllerDB
|
||||||
DEPENDS ${CMAKE_SOURCE_DIR}/gamecontrollerdb.txt)
|
DEPENDS ${CMAKE_SOURCE_DIR}/gamecontrollerdb.txt)
|
||||||
|
|
||||||
# Main executable
|
# Main executable
|
||||||
add_executable(Zelda64Recompiled)
|
add_executable(Zelda64Recompiled MACOSX_BUNDLE)
|
||||||
add_dependencies(Zelda64Recompiled DownloadGameControllerDB)
|
add_dependencies(Zelda64Recompiled DownloadGameControllerDB)
|
||||||
|
|
||||||
# Generate mm_shader_cache.c from the MM shader cache if it exists
|
|
||||||
if (EXISTS ${CMAKE_SOURCE_DIR}/shadercache/mm_shader_cache.bin)
|
|
||||||
set(HAS_MM_SHADER_CACHE TRUE)
|
|
||||||
target_compile_definitions(Zelda64Recompiled PRIVATE HAS_MM_SHADER_CACHE)
|
|
||||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mm_shader_cache.c ${CMAKE_CURRENT_BINARY_DIR}/mm_shader_cache.h
|
|
||||||
COMMAND file_to_c ${CMAKE_SOURCE_DIR}/shadercache/mm_shader_cache.bin mm_shader_cache_bytes ${CMAKE_CURRENT_BINARY_DIR}/mm_shader_cache.c ${CMAKE_CURRENT_BINARY_DIR}/mm_shader_cache.h
|
|
||||||
DEPENDS ${CMAKE_SOURCE_DIR}/shadercache/mm_shader_cache.bin
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set (SOURCES
|
set (SOURCES
|
||||||
${CMAKE_SOURCE_DIR}/src/main/main.cpp
|
${CMAKE_SOURCE_DIR}/src/main/main.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/main/support.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/main/register_overlays.cpp
|
${CMAKE_SOURCE_DIR}/src/main/register_overlays.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/main/register_patches.cpp
|
${CMAKE_SOURCE_DIR}/src/main/register_patches.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/main/rt64_render_context.cpp
|
${CMAKE_SOURCE_DIR}/src/main/rt64_render_context.cpp
|
||||||
|
@ -174,8 +194,8 @@ set (SOURCES
|
||||||
${CMAKE_SOURCE_DIR}/lib/RmlUi/Backends/RmlUi_Platform_SDL.cpp
|
${CMAKE_SOURCE_DIR}/lib/RmlUi/Backends/RmlUi_Platform_SDL.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (HAS_MM_SHADER_CACHE)
|
if (APPLE)
|
||||||
list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/mm_shader_cache.c)
|
list(APPEND SOURCES ${CMAKE_SOURCE_DIR}/src/main/support_apple.mm)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(Zelda64Recompiled PRIVATE
|
target_include_directories(Zelda64Recompiled PRIVATE
|
||||||
|
@ -210,6 +230,11 @@ else()
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
# Disable identical code folding, since this breaks mod function patching as multiple functions can get merged into one.
|
||||||
|
target_link_options(Zelda64Recompiled PRIVATE /OPT:NOICF)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
|
@ -252,6 +277,114 @@ if (WIN32)
|
||||||
target_sources(Zelda64Recompiled PRIVATE ${CMAKE_SOURCE_DIR}/icons/app.rc)
|
target_sources(Zelda64Recompiled PRIVATE ${CMAKE_SOURCE_DIR}/icons/app.rc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
target_include_directories(Zelda64Recompiled PRIVATE ${SDL2_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||||
|
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
target_link_libraries(Zelda64Recompiled PRIVATE ${CMAKE_DL_LIBS} Threads::Threads)
|
||||||
|
|
||||||
|
# Set bundle properties
|
||||||
|
set_target_properties(Zelda64Recompiled PROPERTIES
|
||||||
|
MACOSX_BUNDLE TRUE
|
||||||
|
MACOSX_BUNDLE_BUNDLE_NAME "Zelda64Recompiled"
|
||||||
|
MACOSX_BUNDLE_GUI_IDENTIFIER "com.github.zelda64recompiled"
|
||||||
|
MACOSX_BUNDLE_BUNDLE_VERSION "1.0"
|
||||||
|
MACOSX_BUNDLE_SHORT_VERSION_STRING "1.0"
|
||||||
|
MACOSX_BUNDLE_ICON_FILE "AppIcon.icns"
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_BINARY_DIR}/Info.plist
|
||||||
|
)
|
||||||
|
|
||||||
|
set(ICON_SOURCE ${CMAKE_SOURCE_DIR}/icons/512.png)
|
||||||
|
set(ICONSET_DIR ${CMAKE_BINARY_DIR}/AppIcon.iconset)
|
||||||
|
set(ICNS_FILE ${CMAKE_BINARY_DIR}/resources/AppIcon.icns)
|
||||||
|
|
||||||
|
# Create iconset directory and add PNG file
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${ICONSET_DIR}
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${ICONSET_DIR}
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy ${ICON_SOURCE} ${ICONSET_DIR}/icon_512x512.png
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy ${ICON_SOURCE} ${ICONSET_DIR}/icon_512x512@2x.png
|
||||||
|
COMMAND touch ${ICONSET_DIR}
|
||||||
|
COMMENT "Creating iconset directory and copying PNG file"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Convert iconset to icns
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${ICNS_FILE}
|
||||||
|
DEPENDS ${ICONSET_DIR}
|
||||||
|
COMMAND iconutil -c icns ${ICONSET_DIR} -o ${ICNS_FILE}
|
||||||
|
COMMENT "Converting iconset to icns"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Custom target to ensure icns creation
|
||||||
|
add_custom_target(create_icns ALL DEPENDS ${ICNS_FILE})
|
||||||
|
|
||||||
|
# Set source file properties for the resulting icns file
|
||||||
|
set_source_files_properties(${ICNS_FILE} PROPERTIES
|
||||||
|
MACOSX_PACKAGE_LOCATION "Resources"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add the icns file to the executable target
|
||||||
|
target_sources(Zelda64Recompiled PRIVATE ${ICNS_FILE})
|
||||||
|
|
||||||
|
# Ensure Zelda64Recompiled depends on create_icns
|
||||||
|
add_dependencies(Zelda64Recompiled create_icns)
|
||||||
|
|
||||||
|
# Configure Info.plist
|
||||||
|
configure_file(${CMAKE_SOURCE_DIR}/.github/macos/Info.plist.in ${CMAKE_BINARY_DIR}/Info.plist @ONLY)
|
||||||
|
|
||||||
|
# Install the app bundle
|
||||||
|
install(TARGETS Zelda64Recompiled BUNDLE DESTINATION .)
|
||||||
|
|
||||||
|
# Copy required frameworks to bundle
|
||||||
|
target_link_libraries(Zelda64Recompiled PRIVATE ${MOLTENVK_PATH} ${VULKAN_LOADER_PATH})
|
||||||
|
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/.github/macos/fixup_bundle.cmake
|
||||||
|
)
|
||||||
|
|
||||||
|
# Copy assets folder to the MacOS folder of the app bundle
|
||||||
|
set(TEMP_ASSETS_DIR "${CMAKE_BINARY_DIR}/temp_assets")
|
||||||
|
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets ${TEMP_ASSETS_DIR}
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E remove_directory ${TEMP_ASSETS_DIR}/scss
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${TEMP_ASSETS_DIR} $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/assets
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E remove_directory ${TEMP_ASSETS_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Copy ICD files to macOS Resources folder
|
||||||
|
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/vulkan/icd.d
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/.github/macOS/MoltenVK_icd.json $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/vulkan/icd.d/
|
||||||
|
)
|
||||||
|
|
||||||
|
# Copy controller db file to macOS Resources folder
|
||||||
|
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/gamecontrollerdb.txt $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use install_name_tool to set the RPATH after the build
|
||||||
|
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
|
||||||
|
COMMAND install_name_tool -add_rpath "@executable_path/../Frameworks/" $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/MacOS/Zelda64Recompiled
|
||||||
|
)
|
||||||
|
|
||||||
|
# Apply JIT compilation workaround
|
||||||
|
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E echo "Applying JIT compilation workaround"
|
||||||
|
COMMAND /bin/bash -c "printf '\\x07' | dd of=$<TARGET_FILE:Zelda64Recompiled> bs=1 seek=160 count=1 conv=notrunc"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
# Code sign the app bundle with ad-hoc identity
|
||||||
|
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
|
||||||
|
COMMAND codesign --deep --force --sign - $<TARGET_BUNDLE_DIR:Zelda64Recompiled>
|
||||||
|
COMMENT "Code signing the app bundle with ad-hoc identity"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||||
find_package(SDL2 REQUIRED)
|
find_package(SDL2 REQUIRED)
|
||||||
find_package(X11 REQUIRED)
|
find_package(X11 REQUIRED)
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bottom-left">
|
<div class="bottom-left">
|
||||||
<label>{{version_number}}</label>
|
<label>v{{version_number}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -120,7 +120,8 @@ namespace recomp {
|
||||||
std::vector<InputField> apply_menu;
|
std::vector<InputField> apply_menu;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr const std::vector<InputField>& get_default_mapping_for_input(const DefaultN64Mappings& defaults, const GameInput input) {
|
inline const std::vector<InputField>& get_default_mapping_for_input(const DefaultN64Mappings& defaults, const GameInput input) {
|
||||||
|
static const std::vector<InputField> empty_input_field{};
|
||||||
switch (input) {
|
switch (input) {
|
||||||
case GameInput::A: return defaults.a;
|
case GameInput::A: return defaults.a;
|
||||||
case GameInput::B: return defaults.b;
|
case GameInput::B: return defaults.b;
|
||||||
|
@ -143,7 +144,7 @@ namespace recomp {
|
||||||
case GameInput::TOGGLE_MENU: return defaults.toggle_menu;
|
case GameInput::TOGGLE_MENU: return defaults.toggle_menu;
|
||||||
case GameInput::ACCEPT_MENU: return defaults.accept_menu;
|
case GameInput::ACCEPT_MENU: return defaults.accept_menu;
|
||||||
case GameInput::APPLY_MENU: return defaults.apply_menu;
|
case GameInput::APPLY_MENU: return defaults.apply_menu;
|
||||||
default: return std::vector<InputField>();
|
default: return empty_input_field;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
#ifndef __ZELDA_RENDER_H__
|
#ifndef __ZELDA_RENDER_H__
|
||||||
#define __ZELDA_RENDER_H__
|
#define __ZELDA_RENDER_H__
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include "common/rt64_user_configuration.h"
|
#include "common/rt64_user_configuration.h"
|
||||||
#include "ultramodern/renderer_context.hpp"
|
#include "ultramodern/renderer_context.hpp"
|
||||||
|
#include "librecomp/mods.hpp"
|
||||||
|
|
||||||
namespace RT64 {
|
namespace RT64 {
|
||||||
struct Application;
|
struct Application;
|
||||||
|
@ -29,6 +33,7 @@ namespace zelda64 {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<RT64::Application> app;
|
std::unique_ptr<RT64::Application> app;
|
||||||
|
std::unordered_set<std::filesystem::path> enabled_texture_packs;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<ultramodern::renderer::RendererContext> create_render_context(uint8_t *rdram, ultramodern::renderer::WindowHandle window_handle, bool developer_mode);
|
std::unique_ptr<ultramodern::renderer::RendererContext> create_render_context(uint8_t *rdram, ultramodern::renderer::WindowHandle window_handle, bool developer_mode);
|
||||||
|
@ -36,6 +41,9 @@ namespace zelda64 {
|
||||||
RT64::UserConfiguration::Antialiasing RT64MaxMSAA();
|
RT64::UserConfiguration::Antialiasing RT64MaxMSAA();
|
||||||
bool RT64SamplePositionsSupported();
|
bool RT64SamplePositionsSupported();
|
||||||
bool RT64HighPrecisionFBEnabled();
|
bool RT64HighPrecisionFBEnabled();
|
||||||
|
|
||||||
|
void enable_texture_pack(const recomp::mods::ModHandle& mod);
|
||||||
|
void disable_texture_pack(const recomp::mods::ModHandle& mod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef __ZELDA_SUPPORT_H__
|
||||||
|
#define __ZELDA_SUPPORT_H__
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace zelda64 {
|
||||||
|
void dispatch_on_main_thread(std::function<void()> func);
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
const char* get_bundle_resource_directory();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0a538553330ea5fdb1673708704bb92a854241b9
|
Subproject commit a4f5ee10c8303474d9028468e84845b192e9297d
|
2
lib/rt64
2
lib/rt64
|
@ -1 +1 @@
|
||||||
Subproject commit 88c618c1f8d8089f94e78537e49e0d77798fc0be
|
Subproject commit c648adae38ed8d0342c02ccf3a6063e99d746752
|
|
@ -14,3 +14,7 @@ data_reference_syms_files = [ "Zelda64RecompSyms/mm.us.rev1.datasyms.toml", "Zel
|
||||||
output_binary_path = "patches/patches.bin"
|
output_binary_path = "patches/patches.bin"
|
||||||
# Do not emit warnings for unpaired LO16 values, as clang produces many of them.
|
# Do not emit warnings for unpaired LO16 values, as clang produces many of them.
|
||||||
unpaired_lo16_warnings = false
|
unpaired_lo16_warnings = false
|
||||||
|
# Allow exporting functions and events for mods to use.
|
||||||
|
allow_exports = true
|
||||||
|
# # Enable strict patch mode, validates that patched symbols exist and that non-patch functions aren't symbols.
|
||||||
|
strict_patch_mode = true
|
||||||
|
|
|
@ -67,10 +67,10 @@ RECOMP_PATCH void KaleidoSetup_Update(PlayState* play) {
|
||||||
|
|
||||||
void Sram_SyncWriteToFlash(SramContext* sramCtx, s32 curPage, s32 numPages);
|
void Sram_SyncWriteToFlash(SramContext* sramCtx, s32 curPage, s32 numPages);
|
||||||
|
|
||||||
void autosave_reset_timer();
|
void recomp_reset_autosave_timer();
|
||||||
void autosave_reset_timer_slow();
|
void recomp_reset_autosave_timer_slow();
|
||||||
|
|
||||||
void do_autosave(PlayState* play) {
|
RECOMP_EXPORT void recomp_do_autosave(PlayState* play) {
|
||||||
// Transfer the scene flags into the cycle flags.
|
// Transfer the scene flags into the cycle flags.
|
||||||
Play_SaveCycleSceneFlags(&play->state);
|
Play_SaveCycleSceneFlags(&play->state);
|
||||||
// Transfer the cycle flags into the save buffer. Logic copied from func_8014546C.
|
// Transfer the cycle flags into the save buffer. Logic copied from func_8014546C.
|
||||||
|
@ -99,13 +99,22 @@ void do_autosave(PlayState* play) {
|
||||||
gSaveContext.save.isOwlSave = false;
|
gSaveContext.save.isOwlSave = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @recomp Do not clear the save if the save was an autosave.
|
bool loading_deletes_owl_save = true;
|
||||||
|
|
||||||
|
// @recomp_export void recomp_set_loading_deletes_owl_save(bool new_val): Set whether loading an owl save should also delete it.
|
||||||
|
RECOMP_EXPORT void recomp_set_loading_deletes_owl_save(bool new_val)
|
||||||
|
{
|
||||||
|
loading_deletes_owl_save = new_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @recomp Do not clear the save if the save was an autosave, or if mods have disabled save deletion.
|
||||||
RECOMP_PATCH void func_80147314(SramContext* sramCtx, s32 fileNum) {
|
RECOMP_PATCH void func_80147314(SramContext* sramCtx, s32 fileNum) {
|
||||||
s32 save_type = gSaveContext.save.isOwlSave;
|
s32 save_type = gSaveContext.save.isOwlSave;
|
||||||
gSaveContext.save.isOwlSave = false;
|
gSaveContext.save.isOwlSave = false;
|
||||||
|
|
||||||
// @recomp Prevent owl save/autosave deletion if autosaving is enabled.
|
// @recomp Prevent owl save/autosave deletion if autosaving is enabled, and...
|
||||||
if (!recomp_autosave_enabled()) {
|
// @recomp_use_export_var loading_deletes_owl_save: Prevent owl save deletion if mods disable it.
|
||||||
|
if (!recomp_autosave_enabled() && loading_deletes_owl_save) {
|
||||||
gSaveContext.save.saveInfo.playerData.newf[0] = '\0';
|
gSaveContext.save.saveInfo.playerData.newf[0] = '\0';
|
||||||
gSaveContext.save.saveInfo.playerData.newf[1] = '\0';
|
gSaveContext.save.saveInfo.playerData.newf[1] = '\0';
|
||||||
gSaveContext.save.saveInfo.playerData.newf[2] = '\0';
|
gSaveContext.save.saveInfo.playerData.newf[2] = '\0';
|
||||||
|
@ -176,7 +185,7 @@ RECOMP_PATCH void func_8014546C(SramContext* sramCtx) {
|
||||||
// @recomp Delete the owl save.
|
// @recomp Delete the owl save.
|
||||||
delete_owl_save(sramCtx, gSaveContext.fileNum);
|
delete_owl_save(sramCtx, gSaveContext.fileNum);
|
||||||
// @recomp Reset the autosave timer.
|
// @recomp Reset the autosave timer.
|
||||||
autosave_reset_timer();
|
recomp_reset_autosave_timer();
|
||||||
for (i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) {
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) {
|
||||||
gSaveContext.save.saveInfo.permanentSceneFlags[i].chest = gSaveContext.cycleSceneFlags[i].chest;
|
gSaveContext.save.saveInfo.permanentSceneFlags[i].chest = gSaveContext.cycleSceneFlags[i].chest;
|
||||||
gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0 = gSaveContext.cycleSceneFlags[i].switch0;
|
gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0 = gSaveContext.cycleSceneFlags[i].switch0;
|
||||||
|
@ -344,11 +353,11 @@ void draw_autosave_icon(PlayState* play) {
|
||||||
CLOSE_DISPS(play->state.gfxCtx);
|
CLOSE_DISPS(play->state.gfxCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void show_autosave_icon() {
|
RECOMP_EXPORT void recomp_show_autosave_icon() {
|
||||||
autosave_icon_counter = AUTOSAVE_ICON_TOTAL_FRAMES;
|
autosave_icon_counter = AUTOSAVE_ICON_TOTAL_FRAMES;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 recomp_autosave_interval() {
|
RECOMP_EXPORT u32 recomp_autosave_interval() {
|
||||||
return 2 * 60 * 1000;
|
return 2 * 60 * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,12 +376,12 @@ bool reached_final_three_hours() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void autosave_reset_timer() {
|
RECOMP_EXPORT void recomp_reset_autosave_timer() {
|
||||||
last_autosave_time = osGetTime();
|
last_autosave_time = osGetTime();
|
||||||
extra_autosave_delay_milliseconds = 0;
|
extra_autosave_delay_milliseconds = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void autosave_reset_timer_slow() {
|
RECOMP_EXPORT void recomp_reset_autosave_timer_slow() {
|
||||||
// Set the most recent autosave time in the future to give extra time before an autosave triggers.
|
// Set the most recent autosave time in the future to give extra time before an autosave triggers.
|
||||||
last_autosave_time = osGetTime();
|
last_autosave_time = osGetTime();
|
||||||
extra_autosave_delay_milliseconds = 2 * 60 * 1000;
|
extra_autosave_delay_milliseconds = 2 * 60 * 1000;
|
||||||
|
@ -425,20 +434,20 @@ void autosave_post_play_update(PlayState* play) {
|
||||||
frames_since_autosave_ready >= MIN_FRAMES_SINCE_READY &&
|
frames_since_autosave_ready >= MIN_FRAMES_SINCE_READY &&
|
||||||
time_now - last_autosave_time > (OS_USEC_TO_CYCLES(1000 * (recomp_autosave_interval() + extra_autosave_delay_milliseconds)))
|
time_now - last_autosave_time > (OS_USEC_TO_CYCLES(1000 * (recomp_autosave_interval() + extra_autosave_delay_milliseconds)))
|
||||||
) {
|
) {
|
||||||
do_autosave(play);
|
recomp_do_autosave(play);
|
||||||
show_autosave_icon();
|
recomp_show_autosave_icon();
|
||||||
autosave_reset_timer();
|
recomp_reset_autosave_timer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Update the last autosave time to the current time to prevent autosaving immediately if autosaves are turned back on.
|
// Update the last autosave time to the current time to prevent autosaving immediately if autosaves are turned back on.
|
||||||
autosave_reset_timer();
|
recomp_reset_autosave_timer();
|
||||||
}
|
}
|
||||||
gCanPause = false;
|
gCanPause = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void autosave_init() {
|
void autosave_init() {
|
||||||
autosave_reset_timer_slow();
|
recomp_reset_autosave_timer_slow();
|
||||||
Lib_MemCpy(&prev_save_ctx, &gSaveContext, offsetof(SaveContext, fileNum));
|
Lib_MemCpy(&prev_save_ctx, &gSaveContext, offsetof(SaveContext, fileNum));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,6 +531,9 @@ s32 spawn_entrance_from_autosave_entrance(s16 autosave_entrance) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RECOMP_DECLARE_EVENT(recomp_on_load_save(FileSelectState* fileSelect, SramContext* sramCtx));
|
||||||
|
RECOMP_DECLARE_EVENT(recomp_after_load_save(FileSelectState* fileSelect, SramContext* sramCtx));
|
||||||
|
|
||||||
// @recomp Patched to change the entrance for autosaves and initialize autosaves.
|
// @recomp Patched to change the entrance for autosaves and initialize autosaves.
|
||||||
RECOMP_PATCH void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCtx) {
|
RECOMP_PATCH void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCtx) {
|
||||||
s32 i;
|
s32 i;
|
||||||
|
@ -530,6 +542,9 @@ RECOMP_PATCH void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCt
|
||||||
s32 pad1;
|
s32 pad1;
|
||||||
s32 fileNum;
|
s32 fileNum;
|
||||||
|
|
||||||
|
// @recomp_event recomp_on_load_save(FileSelectState* fileSelect, SramContext* sramCtx): A save-file was just chosen.
|
||||||
|
recomp_on_load_save(fileSelect, sramCtx);
|
||||||
|
|
||||||
if (gSaveContext.flashSaveAvailable) {
|
if (gSaveContext.flashSaveAvailable) {
|
||||||
bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE);
|
bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE);
|
||||||
|
|
||||||
|
@ -653,15 +668,34 @@ RECOMP_PATCH void Sram_OpenSave(FileSelectState* fileSelect, SramContext* sramCt
|
||||||
|
|
||||||
// @recomp Initialize the autosave state tracking.
|
// @recomp Initialize the autosave state tracking.
|
||||||
autosave_init();
|
autosave_init();
|
||||||
|
|
||||||
|
// @recomp_event recomp_after_load_save(FileSelectState* fileSelect, SramContext* sramCtx): The save has finished loading.
|
||||||
|
recomp_after_load_save(fileSelect, sramCtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool moon_crash_resets_save = true;
|
||||||
|
|
||||||
|
// @recomp_export void recomp_set_moon_crash_resets_save(bool new_val): Set whether a moon crash should revert the player's save data.
|
||||||
|
RECOMP_EXPORT void recomp_set_moon_crash_resets_save(bool new_val)
|
||||||
|
{
|
||||||
|
moon_crash_resets_save = new_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern s32 Actor_ProcessTalkRequest(Actor* actor, GameState* gameState);
|
extern s32 Actor_ProcessTalkRequest(Actor* actor, GameState* gameState);
|
||||||
|
|
||||||
|
RECOMP_DECLARE_EVENT(recomp_on_moon_crash(SramContext* sramCtx));
|
||||||
|
RECOMP_DECLARE_EVENT(recomp_after_moon_crash(SramContext* sramCtx));
|
||||||
|
|
||||||
// @recomp Reset the autosave timer when the moon crashes.
|
// @recomp Reset the autosave timer when the moon crashes.
|
||||||
RECOMP_PATCH void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) {
|
RECOMP_PATCH void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) {
|
||||||
s32 i;
|
s32 i;
|
||||||
s32 cutsceneIndex = gSaveContext.save.cutsceneIndex;
|
s32 cutsceneIndex = gSaveContext.save.cutsceneIndex;
|
||||||
|
|
||||||
|
// @recomp_event recomp_on_moon_crash(SramContext* sramCtx): A moon crash has just been triggered.
|
||||||
|
recomp_on_moon_crash(sramCtx);
|
||||||
|
|
||||||
|
if (moon_crash_resets_save)
|
||||||
|
{
|
||||||
bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE);
|
bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE);
|
||||||
|
|
||||||
if (SysFlashrom_ReadData(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2],
|
if (SysFlashrom_ReadData(sramCtx->saveBuf, gFlashSaveStartPages[gSaveContext.fileNum * 2],
|
||||||
|
@ -676,6 +710,7 @@ RECOMP_PATCH void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) {
|
||||||
Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, sizeof(Save));
|
Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, sizeof(Save));
|
||||||
}
|
}
|
||||||
gSaveContext.save.cutsceneIndex = cutsceneIndex;
|
gSaveContext.save.cutsceneIndex = cutsceneIndex;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_COUNT(gSaveContext.eventInf); i++) {
|
for (i = 0; i < ARRAY_COUNT(gSaveContext.eventInf); i++) {
|
||||||
gSaveContext.eventInf[i] = 0;
|
gSaveContext.eventInf[i] = 0;
|
||||||
|
@ -705,25 +740,56 @@ RECOMP_PATCH void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) {
|
||||||
gSaveContext.jinxTimer = 0;
|
gSaveContext.jinxTimer = 0;
|
||||||
|
|
||||||
// @recomp Use the slow autosave timer to give the player extra time to respond to the moon crashing to decide if they want to reload their autosave.
|
// @recomp Use the slow autosave timer to give the player extra time to respond to the moon crashing to decide if they want to reload their autosave.
|
||||||
autosave_reset_timer_slow();
|
recomp_reset_autosave_timer_slow();
|
||||||
|
|
||||||
|
// @recomp_event recomp_after_moon_crash(SramContext* sramCtx): The effects of moon crash have been written.
|
||||||
|
recomp_after_moon_crash(sramCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// @recomp If autosave is enabled, skip the part of the owl statue dialog that talks about the file being deleted on load, since it's not true.
|
bool owls_save_and_quit = true;
|
||||||
|
|
||||||
|
// @recomp_export void recomp_set_owls_save_and_quit(bool new_val): Set if owls should use their code to save and quit. If false is passed, owl saves now do nothing.
|
||||||
|
RECOMP_EXPORT void recomp_set_owls_save_and_quit(bool new_val)
|
||||||
|
{
|
||||||
|
owls_save_and_quit = new_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
RECOMP_DECLARE_EVENT(recomp_on_owl_update(ObjWarpstone* this, PlayState* play));
|
||||||
|
RECOMP_DECLARE_EVENT(recomp_on_owl_save(ObjWarpstone* this, PlayState* play));
|
||||||
|
RECOMP_DECLARE_EVENT(recomp_after_owl_save(ObjWarpstone* this, PlayState* play));
|
||||||
|
|
||||||
|
// @recomp If autosave is enabled or owl save deletion is disabled, skip the part of the owl statue dialog that talks about the file being deleted on load, since it's not true.
|
||||||
RECOMP_PATCH void ObjWarpstone_Update(Actor* thisx, PlayState* play) {
|
RECOMP_PATCH void ObjWarpstone_Update(Actor* thisx, PlayState* play) {
|
||||||
ObjWarpstone* this = (ObjWarpstone*)thisx;
|
ObjWarpstone* this = (ObjWarpstone*)thisx;
|
||||||
s32 pad;
|
s32 pad;
|
||||||
|
|
||||||
|
// @recomp_event recomp_on_owl_update(ObjWarpstone* this, PlayState* play): Allow mods to handle owl update frames.
|
||||||
|
recomp_on_owl_update(this, play);
|
||||||
|
|
||||||
if (this->isTalking) {
|
if (this->isTalking) {
|
||||||
if (Actor_TextboxIsClosing(&this->dyna.actor, play)) {
|
if (Actor_TextboxIsClosing(&this->dyna.actor, play)) {
|
||||||
this->isTalking = false;
|
this->isTalking = false;
|
||||||
} else if ((Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE) && Message_ShouldAdvance(play)) {
|
} else if ((Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE) && Message_ShouldAdvance(play)) {
|
||||||
if (play->msgCtx.choiceIndex != 0) {
|
if (play->msgCtx.choiceIndex != 0) {
|
||||||
|
// @recomp_event recomp_on_owl_save(ObjWarpstone* this, PlayState* play): The player chose to save from an owl statue.
|
||||||
|
recomp_on_owl_save(this, play);
|
||||||
|
|
||||||
Audio_PlaySfx_MessageDecide();
|
Audio_PlaySfx_MessageDecide();
|
||||||
|
|
||||||
|
// @recomp_use_export_var owls_save_and_quit: Only use normal owl save if quit flag is set.
|
||||||
|
if (owls_save_and_quit) {
|
||||||
play->msgCtx.msgMode = MSGMODE_OWL_SAVE_0;
|
play->msgCtx.msgMode = MSGMODE_OWL_SAVE_0;
|
||||||
|
} else {
|
||||||
|
Message_CloseTextbox(play);
|
||||||
|
}
|
||||||
|
|
||||||
play->msgCtx.unk120D6 = 0;
|
play->msgCtx.unk120D6 = 0;
|
||||||
play->msgCtx.unk120D4 = 0;
|
play->msgCtx.unk120D4 = 0;
|
||||||
gSaveContext.save.owlWarpId = OBJ_WARPSTONE_GET_OWL_WARP_ID(&this->dyna.actor);
|
gSaveContext.save.owlWarpId = OBJ_WARPSTONE_GET_OWL_WARP_ID(&this->dyna.actor);
|
||||||
|
|
||||||
|
// @recomp_event recomp_after_owl_save(ObjWarpstone* this, PlayState* play): Owl save is finished.
|
||||||
|
recomp_after_owl_save(this, play);
|
||||||
} else {
|
} else {
|
||||||
Message_CloseTextbox(play);
|
Message_CloseTextbox(play);
|
||||||
}
|
}
|
||||||
|
@ -734,8 +800,8 @@ RECOMP_PATCH void ObjWarpstone_Update(Actor* thisx, PlayState* play) {
|
||||||
Actor_OfferTalkNearColChkInfoCylinder(&this->dyna.actor, play);
|
Actor_OfferTalkNearColChkInfoCylinder(&this->dyna.actor, play);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @recomp Skip the text talking about the save being deleted on load, if autosave is enabled.
|
// @recomp_use_export_var loading_deletes_owl_save: Skip the text talking about the save being deleted on load, if autosave is enabled or if owl save deletion is disabled.
|
||||||
if (recomp_autosave_enabled()) {
|
if (recomp_autosave_enabled() || !loading_deletes_owl_save) {
|
||||||
if (this->isTalking && play->msgCtx.currentTextId == 0xC01 && play->msgCtx.msgBufPos == 269) {
|
if (this->isTalking && play->msgCtx.currentTextId == 0xC01 && play->msgCtx.msgBufPos == 269) {
|
||||||
play->msgCtx.msgBufPos = 530;
|
play->msgCtx.msgBufPos = 530;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,11 @@
|
||||||
#define RECOMP_EXPORT __attribute__((section(".recomp_export")))
|
#define RECOMP_EXPORT __attribute__((section(".recomp_export")))
|
||||||
#define RECOMP_PATCH __attribute__((section(".recomp_patch")))
|
#define RECOMP_PATCH __attribute__((section(".recomp_patch")))
|
||||||
#define RECOMP_FORCE_PATCH __attribute__((section(".recomp_force_patch")))
|
#define RECOMP_FORCE_PATCH __attribute__((section(".recomp_force_patch")))
|
||||||
|
#define RECOMP_DECLARE_EVENT(func) \
|
||||||
|
_Pragma("GCC diagnostic push") \
|
||||||
|
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") \
|
||||||
|
__attribute__((noinline, weak, used, section(".recomp_event"))) void func {} \
|
||||||
|
_Pragma("GCC diagnostic pop")
|
||||||
|
|
||||||
// TODO fix renaming symbols in patch recompilation
|
// TODO fix renaming symbols in patch recompilation
|
||||||
#define osCreateMesgQueue osCreateMesgQueue_recomp
|
#define osCreateMesgQueue osCreateMesgQueue_recomp
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
RAMBASE = 0x80801000; /* Used to hold any new symbols */
|
RAMBASE = 0x80801000; /* Used to hold any new symbols */
|
||||||
EXTRA_RAM_SIZE = 0x01000000; /* Amount of extra ram allocated by recomp */
|
PATCH_RAM_END = 0x81000000; /* Amount of extra ram allocated by recomp */
|
||||||
|
|
||||||
MEMORY {
|
MEMORY {
|
||||||
extram : ORIGIN = RAMBASE, LENGTH = 64M
|
extram : ORIGIN = RAMBASE, LENGTH = 64M
|
||||||
|
@ -12,10 +12,11 @@ SECTIONS {
|
||||||
.text : { *(.text*) } >extram AT >rom
|
.text : { *(.text*) } >extram AT >rom
|
||||||
.recomp_patch : { *(.recomp_patch*) *(.recomp_force_patch*) } >extram AT >rom
|
.recomp_patch : { *(.recomp_patch*) *(.recomp_force_patch*) } >extram AT >rom
|
||||||
.recomp_export : { *(.recomp_export*) } >extram AT >rom
|
.recomp_export : { *(.recomp_export*) } >extram AT >rom
|
||||||
|
.recomp_event : { *(.recomp_event*) } >extram AT >rom
|
||||||
.rodata : { *(.rodata*) } >extram AT >rom
|
.rodata : { *(.rodata*) } >extram AT >rom
|
||||||
.data : { *(.data*) } >extram AT >rom
|
.data : { *(.data*) } >extram AT >rom
|
||||||
.bss (NOLOAD) : { *(.bss*) *(COMMON) } >extram
|
.bss (NOLOAD) : { *(.bss*) *(COMMON) } >extram
|
||||||
ASSERT(. < RAMBASE + EXTRA_RAM_SIZE, "Maxed out recomp extra ram")
|
ASSERT(. <= PATCH_RAM_END, "Maxed out recomp extra ram")
|
||||||
|
|
||||||
.reloc 0 : { *(.reloc*) }
|
.reloc 0 : { *(.reloc*) }
|
||||||
.symtab 0 : { *(.symtab) }
|
.symtab 0 : { *(.symtab) }
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
extern Input D_801F6C18;
|
extern Input D_801F6C18;
|
||||||
|
|
||||||
|
RECOMP_DECLARE_EVENT(recomp_on_play_main(PlayState* play));
|
||||||
|
RECOMP_DECLARE_EVENT(recomp_on_play_update(PlayState* play));
|
||||||
|
RECOMP_DECLARE_EVENT(recomp_after_play_update(PlayState* play));
|
||||||
|
|
||||||
void controls_play_update(PlayState* play) {
|
void controls_play_update(PlayState* play) {
|
||||||
gSaveContext.options.zTargetSetting = recomp_get_targeting_mode();
|
gSaveContext.options.zTargetSetting = recomp_get_targeting_mode();
|
||||||
}
|
}
|
||||||
|
@ -13,6 +17,9 @@ RECOMP_PATCH void Play_Main(GameState* thisx) {
|
||||||
static Input* prevInput = NULL;
|
static Input* prevInput = NULL;
|
||||||
PlayState* this = (PlayState*)thisx;
|
PlayState* this = (PlayState*)thisx;
|
||||||
|
|
||||||
|
// @recomp_event recomp_on_play_main(PlayState* play): Allow mods to execute code every frame.
|
||||||
|
recomp_on_play_main(this);
|
||||||
|
|
||||||
// @recomp
|
// @recomp
|
||||||
debug_play_update(this);
|
debug_play_update(this);
|
||||||
controls_play_update(this);
|
controls_play_update(this);
|
||||||
|
@ -32,7 +39,15 @@ RECOMP_PATCH void Play_Main(GameState* thisx) {
|
||||||
this->state.gfxCtx = NULL;
|
this->state.gfxCtx = NULL;
|
||||||
}
|
}
|
||||||
camera_pre_play_update(this);
|
camera_pre_play_update(this);
|
||||||
|
|
||||||
|
// @recomp_event recomp_on_play_update(PlayState* play): Play_Update is about to be called.
|
||||||
|
recomp_on_play_update(this);
|
||||||
|
|
||||||
Play_Update(this);
|
Play_Update(this);
|
||||||
|
|
||||||
|
// @recomp_event recomp_after_play_update(PlayState* play): Play_Update was called.
|
||||||
|
recomp_after_play_update(this);
|
||||||
|
|
||||||
camera_post_play_update(this);
|
camera_post_play_update(this);
|
||||||
analog_cam_post_play_update(this);
|
analog_cam_post_play_update(this);
|
||||||
autosave_post_play_update(this);
|
autosave_post_play_update(this);
|
||||||
|
|
|
@ -6,7 +6,7 @@ void* proutPrintf(void* dst, const char* fmt, size_t size) {
|
||||||
return (void*)1;
|
return (void*)1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int recomp_printf(const char* fmt, ...) {
|
RECOMP_EXPORT int recomp_printf(const char* fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ void Main_InitMemory(void);
|
||||||
void Main_InitScreen(void);
|
void Main_InitScreen(void);
|
||||||
|
|
||||||
|
|
||||||
|
RECOMP_DECLARE_EVENT(recomp_on_init());
|
||||||
|
|
||||||
// @recomp Patched to load the code segment in the recomp runtime.
|
// @recomp Patched to load the code segment in the recomp runtime.
|
||||||
RECOMP_PATCH void Main_Init(void) {
|
RECOMP_PATCH void Main_Init(void) {
|
||||||
DmaRequest dmaReq;
|
DmaRequest dmaReq;
|
||||||
|
@ -14,6 +16,9 @@ RECOMP_PATCH void Main_Init(void) {
|
||||||
OSMesg msg[1];
|
OSMesg msg[1];
|
||||||
size_t prevSize;
|
size_t prevSize;
|
||||||
|
|
||||||
|
// @recomp_event recomp_on_init(): Allow mods to initialize themselves once.
|
||||||
|
recomp_on_init();
|
||||||
|
|
||||||
osCreateMesgQueue(&mq, msg, ARRAY_COUNT(msg));
|
osCreateMesgQueue(&mq, msg, ARRAY_COUNT(msg));
|
||||||
|
|
||||||
prevSize = gDmaMgrDmaBuffSize;
|
prevSize = gDmaMgrDmaBuffSize;
|
||||||
|
|
|
@ -1266,7 +1266,7 @@ extern Gfx ovl_En_Tanron1_DL_001888[];
|
||||||
extern Gfx ovl_En_Tanron1_DL_001900[];
|
extern Gfx ovl_En_Tanron1_DL_001900[];
|
||||||
|
|
||||||
// @recomp Patched to interpolate the moths that circle torches.
|
// @recomp Patched to interpolate the moths that circle torches.
|
||||||
void func_80BB5AAC(EnTanron1* this, PlayState* play) {
|
RECOMP_PATCH void func_80BB5AAC(EnTanron1* this, PlayState* play) {
|
||||||
EnTanron1Struct* ptrBase = &this->unk_160[0];
|
EnTanron1Struct* ptrBase = &this->unk_160[0];
|
||||||
s16 i;
|
s16 i;
|
||||||
u8 flag = 0;
|
u8 flag = 0;
|
||||||
|
|
|
@ -56,9 +56,10 @@ RECOMP_PATCH void Graph_SetNextGfxPool(GraphicsContext* gfxCtx) {
|
||||||
gSPEndDisplayList(&gGfxMasterDL->disps[4]);
|
gSPEndDisplayList(&gGfxMasterDL->disps[4]);
|
||||||
gSPBranchList(&gGfxMasterDL->debugDisp[0], bigger_pool->debugBuffer);
|
gSPBranchList(&gGfxMasterDL->debugDisp[0], bigger_pool->debugBuffer);
|
||||||
|
|
||||||
// @recomp Enable RT64 extended GBI mode and set the current framerate
|
// @recomp Enable RT64 extended GBI mode and extended rdram.
|
||||||
OPEN_DISPS(gfxCtx);
|
OPEN_DISPS(gfxCtx);
|
||||||
gEXEnable(POLY_OPA_DISP++);
|
gEXEnable(POLY_OPA_DISP++);
|
||||||
|
gEXSetRDRAMExtended(POLY_OPA_DISP++, 1);
|
||||||
CLOSE_DISPS(gfxCtx);
|
CLOSE_DISPS(gfxCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,14 @@
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#include "common/rt64_apple.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr std::u8string_view general_filename = u8"general.json";
|
constexpr std::u8string_view general_filename = u8"general.json";
|
||||||
constexpr std::u8string_view graphics_filename = u8"graphics.json";
|
constexpr std::u8string_view graphics_filename = u8"graphics.json";
|
||||||
constexpr std::u8string_view controls_filename = u8"controls.json";
|
constexpr std::u8string_view controls_filename = u8"controls.json";
|
||||||
constexpr std::u8string_view sound_filename = u8"sound.json";
|
constexpr std::u8string_view sound_filename = u8"sound.json";
|
||||||
constexpr std::u8string_view program_id = u8"Zelda64Recompiled";
|
|
||||||
|
|
||||||
constexpr auto res_default = ultramodern::renderer::Resolution::Auto;
|
constexpr auto res_default = ultramodern::renderer::Resolution::Auto;
|
||||||
constexpr auto hr_default = ultramodern::renderer::HUDRatioMode::Clamp16x9;
|
constexpr auto hr_default = ultramodern::renderer::HUDRatioMode::Clamp16x9;
|
||||||
|
@ -146,8 +147,8 @@ std::filesystem::path zelda64::get_app_folder_path() {
|
||||||
}
|
}
|
||||||
|
|
||||||
CoTaskMemFree(known_path);
|
CoTaskMemFree(known_path);
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__) || defined(__APPLE__)
|
||||||
// check for APP_FOLDER_PATH env var used by AppImage
|
// check for APP_FOLDER_PATH env var
|
||||||
if (getenv("APP_FOLDER_PATH") != nullptr) {
|
if (getenv("APP_FOLDER_PATH") != nullptr) {
|
||||||
return std::filesystem::path{getenv("APP_FOLDER_PATH")};
|
return std::filesystem::path{getenv("APP_FOLDER_PATH")};
|
||||||
}
|
}
|
||||||
|
@ -155,7 +156,11 @@ std::filesystem::path zelda64::get_app_folder_path() {
|
||||||
const char *homedir;
|
const char *homedir;
|
||||||
|
|
||||||
if ((homedir = getenv("HOME")) == nullptr) {
|
if ((homedir = getenv("HOME")) == nullptr) {
|
||||||
|
#if defined(__linux__)
|
||||||
homedir = getpwuid(getuid())->pw_dir;
|
homedir = getpwuid(getuid())->pw_dir;
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
homedir = GetHomeDirectory();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (homedir != nullptr) {
|
if (homedir != nullptr) {
|
||||||
|
|
|
@ -25,8 +25,10 @@
|
||||||
#include "zelda_config.h"
|
#include "zelda_config.h"
|
||||||
#include "zelda_sound.h"
|
#include "zelda_sound.h"
|
||||||
#include "zelda_render.h"
|
#include "zelda_render.h"
|
||||||
|
#include "zelda_support.h"
|
||||||
#include "ovl_patches.hpp"
|
#include "ovl_patches.hpp"
|
||||||
#include "librecomp/game.hpp"
|
#include "librecomp/game.hpp"
|
||||||
|
#include "librecomp/mods.hpp"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
@ -36,12 +38,14 @@
|
||||||
|
|
||||||
#include "../../lib/rt64/src/contrib/stb/stb_image.h"
|
#include "../../lib/rt64/src/contrib/stb/stb_image.h"
|
||||||
|
|
||||||
|
const std::string version_string = "1.2.0-dev";
|
||||||
|
|
||||||
template<typename... Ts>
|
template<typename... Ts>
|
||||||
void exit_error(const char* str, Ts ...args) {
|
void exit_error(const char* str, Ts ...args) {
|
||||||
// TODO pop up an error
|
// TODO pop up an error
|
||||||
((void)fprintf(stderr, str, args), ...);
|
((void)fprintf(stderr, str, args), ...);
|
||||||
assert(false);
|
assert(false);
|
||||||
std::quick_exit(EXIT_FAILURE);
|
ULTRAMODERN_QUICK_EXIT();
|
||||||
}
|
}
|
||||||
|
|
||||||
ultramodern::gfx_callbacks_t::gfx_data_t create_gfx() {
|
ultramodern::gfx_callbacks_t::gfx_data_t create_gfx() {
|
||||||
|
@ -115,7 +119,12 @@ bool SetImageAsIcon(const char* filename, SDL_Window* window)
|
||||||
SDL_Window* window;
|
SDL_Window* window;
|
||||||
|
|
||||||
ultramodern::renderer::WindowHandle create_window(ultramodern::gfx_callbacks_t::gfx_data_t) {
|
ultramodern::renderer::WindowHandle create_window(ultramodern::gfx_callbacks_t::gfx_data_t) {
|
||||||
window = SDL_CreateWindow("Zelda 64: Recompiled", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1600, 960, SDL_WINDOW_RESIZABLE );
|
uint32_t window_flags = SDL_WINDOW_RESIZABLE;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
window_flags |= SDL_WINDOW_METAL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
window = SDL_CreateWindow("Zelda 64: Recompiled", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1600, 960, window_flags );
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
SetImageAsIcon("icons/512.png",window);
|
SetImageAsIcon("icons/512.png",window);
|
||||||
if (ultramodern::renderer::get_graphics_config().wm_option == ultramodern::renderer::WindowMode::Fullscreen) { // TODO: Remove once RT64 gets native fullscreen support on Linux
|
if (ultramodern::renderer::get_graphics_config().wm_option == ultramodern::renderer::WindowMode::Fullscreen) { // TODO: Remove once RT64 gets native fullscreen support on Linux
|
||||||
|
@ -143,6 +152,9 @@ ultramodern::renderer::WindowHandle create_window(ultramodern::gfx_callbacks_t::
|
||||||
}
|
}
|
||||||
|
|
||||||
return ultramodern::renderer::WindowHandle{ wmInfo.info.x11.display, wmInfo.info.x11.window };
|
return ultramodern::renderer::WindowHandle{ wmInfo.info.x11.display, wmInfo.info.x11.window };
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
SDL_MetalView view = SDL_Metal_CreateView(window);
|
||||||
|
return ultramodern::renderer::WindowHandle{ wmInfo.info.cocoa.window, SDL_Metal_GetLayer(view) };
|
||||||
#else
|
#else
|
||||||
static_assert(false && "Unimplemented");
|
static_assert(false && "Unimplemented");
|
||||||
#endif
|
#endif
|
||||||
|
@ -327,6 +339,7 @@ std::vector<recomp::GameEntry> supported_games = {
|
||||||
.rom_hash = 0xEF18B4A9E2386169ULL,
|
.rom_hash = 0xEF18B4A9E2386169ULL,
|
||||||
.internal_name = "ZELDA MAJORA'S MASK",
|
.internal_name = "ZELDA MAJORA'S MASK",
|
||||||
.game_id = u8"mm.n64.us.1.0",
|
.game_id = u8"mm.n64.us.1.0",
|
||||||
|
.mod_game_id = "mm",
|
||||||
.is_enabled = true,
|
.is_enabled = true,
|
||||||
.entrypoint_address = get_entrypoint_address(),
|
.entrypoint_address = get_entrypoint_address(),
|
||||||
.entrypoint = recomp_entrypoint,
|
.entrypoint = recomp_entrypoint,
|
||||||
|
@ -524,7 +537,23 @@ void release_preload(PreloadContext& context) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void enable_texture_pack(recomp::mods::ModContext& context, const recomp::mods::ModHandle& mod) {
|
||||||
|
(void)context;
|
||||||
|
zelda64::renderer::enable_texture_pack(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable_texture_pack(recomp::mods::ModContext& context, const recomp::mods::ModHandle& mod) {
|
||||||
|
(void)context;
|
||||||
|
zelda64::renderer::disable_texture_pack(mod);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
recomp::Version project_version{};
|
||||||
|
if (!recomp::Version::from_string(version_string, project_version)) {
|
||||||
|
ultramodern::error_handling::message_box(("Invalid version string: " + version_string).c_str());
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
// Map this executable into memory and lock it, which should keep it in physical memory. This ensures
|
// Map this executable into memory and lock it, which should keep it in physical memory. This ensures
|
||||||
// that there are no stutters from the OS having to load new pages of the executable whenever a new code page is run.
|
// that there are no stutters from the OS having to load new pages of the executable whenever a new code page is run.
|
||||||
PreloadContext preload_context;
|
PreloadContext preload_context;
|
||||||
|
@ -563,11 +592,18 @@ int main(int argc, char** argv) {
|
||||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||||
reset_audio(48000);
|
reset_audio(48000);
|
||||||
|
|
||||||
// Source controller mappings file
|
#if defined(__APPLE__)
|
||||||
if (SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt") < 0) {
|
const char* resource_directory = zelda64::get_bundle_resource_directory();
|
||||||
|
std::string mapping_file_path = std::string(resource_directory) + "gamecontrollerdb.txt";
|
||||||
|
#else
|
||||||
|
std::string mapping_file_path = "gamecontrollerdb.txt";
|
||||||
|
#endif
|
||||||
|
if (SDL_GameControllerAddMappingsFromFile(mapping_file_path.c_str()) < 0) {
|
||||||
fprintf(stderr, "Failed to load controller mappings: %s\n", SDL_GetError());
|
fprintf(stderr, "Failed to load controller mappings: %s\n", SDL_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recomp::register_config_path(zelda64::get_app_folder_path());
|
||||||
|
|
||||||
// Register supported games and patches
|
// Register supported games and patches
|
||||||
for (const auto& game : supported_games) {
|
for (const auto& game : supported_games) {
|
||||||
recomp::register_game(game);
|
recomp::register_game(game);
|
||||||
|
@ -575,8 +611,6 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
zelda64::register_overlays();
|
zelda64::register_overlays();
|
||||||
zelda64::register_patches();
|
zelda64::register_patches();
|
||||||
|
|
||||||
recomp::register_config_path(zelda64::get_app_folder_path());
|
|
||||||
zelda64::load_config();
|
zelda64::load_config();
|
||||||
|
|
||||||
recomp::rsp::callbacks_t rsp_callbacks{
|
recomp::rsp::callbacks_t rsp_callbacks{
|
||||||
|
@ -619,7 +653,48 @@ int main(int argc, char** argv) {
|
||||||
.get_game_thread_name = zelda64::get_game_thread_name,
|
.get_game_thread_name = zelda64::get_game_thread_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Register the texture pack content type with rt64.json as its content file.
|
||||||
|
recomp::mods::ModContentType texture_pack_content_type{
|
||||||
|
.content_filename = "rt64.json",
|
||||||
|
.allow_runtime_toggle = true,
|
||||||
|
.on_enabled = enable_texture_pack,
|
||||||
|
.on_disabled = disable_texture_pack,
|
||||||
|
};
|
||||||
|
auto texture_pack_content_type_id = recomp::mods::register_mod_content_type(texture_pack_content_type);
|
||||||
|
|
||||||
|
// Register the .rtz texture pack file format with the previous content type as its only allowed content type.
|
||||||
|
recomp::mods::register_mod_container_type("rtz", std::vector{ texture_pack_content_type_id }, false);
|
||||||
|
|
||||||
|
recomp::mods::scan_mods();
|
||||||
|
|
||||||
|
printf("Found mods:\n");
|
||||||
|
for (const auto& mod : recomp::mods::get_mod_details("mm")) {
|
||||||
|
printf(" %s(%s)\n", mod.mod_id.c_str(), mod.version.to_string().c_str());
|
||||||
|
if (!mod.authors.empty()) {
|
||||||
|
printf(" Authors: %s", mod.authors[0].c_str());
|
||||||
|
for (size_t author_index = 1; author_index < mod.authors.size(); author_index++) {
|
||||||
|
const std::string& author = mod.authors[author_index];
|
||||||
|
printf(", %s", author.c_str());
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
printf(" Runtime toggleable: %d\n", mod.runtime_toggleable);
|
||||||
|
}
|
||||||
|
if (!mod.dependencies.empty()) {
|
||||||
|
printf(" Dependencies: %s:%s", mod.dependencies[0].mod_id.c_str(), mod.dependencies[0].version.to_string().c_str());
|
||||||
|
for (size_t dep_index = 1; dep_index < mod.dependencies.size(); dep_index++) {
|
||||||
|
const recomp::mods::Dependency& dep = mod.dependencies[dep_index];
|
||||||
|
printf(", %s:%s", dep.mod_id.c_str(), dep.version.to_string().c_str());
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
// TODO load all mods as a temporary solution to not having a UI yet.
|
||||||
|
recomp::mods::enable_mod(mod.mod_id, true);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
recomp::start(
|
recomp::start(
|
||||||
|
64 * 1024 * 1024, // 64MB to have plenty of room for loading mods
|
||||||
|
project_version,
|
||||||
{},
|
{},
|
||||||
rsp_callbacks,
|
rsp_callbacks,
|
||||||
renderer_callbacks,
|
renderer_callbacks,
|
||||||
|
|
|
@ -7,4 +7,6 @@
|
||||||
|
|
||||||
void zelda64::register_patches() {
|
void zelda64::register_patches() {
|
||||||
recomp::overlays::register_patches(mm_patches_bin, sizeof(mm_patches_bin), section_table, ARRLEN(section_table));
|
recomp::overlays::register_patches(mm_patches_bin, sizeof(mm_patches_bin), section_table, ARRLEN(section_table));
|
||||||
|
recomp::overlays::register_base_exports(export_table);
|
||||||
|
recomp::overlays::register_base_events(event_names);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#define HLSL_CPU
|
#define HLSL_CPU
|
||||||
#include "hle/rt64_application.h"
|
#include "hle/rt64_application.h"
|
||||||
|
@ -10,6 +11,13 @@
|
||||||
|
|
||||||
#include "zelda_render.h"
|
#include "zelda_render.h"
|
||||||
#include "recomp_ui.h"
|
#include "recomp_ui.h"
|
||||||
|
#include "concurrentqueue.h"
|
||||||
|
|
||||||
|
// Helper class for variant visiting.
|
||||||
|
template<class... Ts>
|
||||||
|
struct overloaded : Ts... { using Ts::operator()...; };
|
||||||
|
template<class... Ts>
|
||||||
|
overloaded(Ts...) -> overloaded<Ts...>;
|
||||||
|
|
||||||
static RT64::UserConfiguration::Antialiasing device_max_msaa = RT64::UserConfiguration::Antialiasing::None;
|
static RT64::UserConfiguration::Antialiasing device_max_msaa = RT64::UserConfiguration::Antialiasing::None;
|
||||||
static bool sample_positions_supported = false;
|
static bool sample_positions_supported = false;
|
||||||
|
@ -18,6 +26,18 @@ static bool high_precision_fb_enabled = false;
|
||||||
static uint8_t DMEM[0x1000];
|
static uint8_t DMEM[0x1000];
|
||||||
static uint8_t IMEM[0x1000];
|
static uint8_t IMEM[0x1000];
|
||||||
|
|
||||||
|
struct TexturePackEnableAction {
|
||||||
|
std::filesystem::path path;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TexturePackDisableAction {
|
||||||
|
std::filesystem::path path;
|
||||||
|
};
|
||||||
|
|
||||||
|
using TexturePackAction = std::variant<TexturePackEnableAction, TexturePackDisableAction>;
|
||||||
|
|
||||||
|
static moodycamel::ConcurrentQueue<TexturePackAction> texture_pack_action_queue;
|
||||||
|
|
||||||
unsigned int MI_INTR_REG = 0;
|
unsigned int MI_INTR_REG = 0;
|
||||||
|
|
||||||
unsigned int DPC_START_REG = 0;
|
unsigned int DPC_START_REG = 0;
|
||||||
|
@ -187,7 +207,7 @@ zelda64::renderer::RT64Context::RT64Context(uint8_t* rdram, ultramodern::rendere
|
||||||
appCore.window.window = window_handle.window;
|
appCore.window.window = window_handle.window;
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
appCore.window.window = window_handle.window;
|
appCore.window.window = window_handle.window;
|
||||||
appCore.window.view = window_handle.view;
|
appCore.window.layer = window_handle.view;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
appCore.checkInterrupts = dummy_check_interrupts;
|
appCore.checkInterrupts = dummy_check_interrupts;
|
||||||
|
@ -286,6 +306,32 @@ zelda64::renderer::RT64Context::RT64Context(uint8_t* rdram, ultramodern::rendere
|
||||||
zelda64::renderer::RT64Context::~RT64Context() = default;
|
zelda64::renderer::RT64Context::~RT64Context() = default;
|
||||||
|
|
||||||
void zelda64::renderer::RT64Context::send_dl(const OSTask* task) {
|
void zelda64::renderer::RT64Context::send_dl(const OSTask* task) {
|
||||||
|
bool packs_disabled = false;
|
||||||
|
TexturePackAction cur_action;
|
||||||
|
while (texture_pack_action_queue.try_dequeue(cur_action)) {
|
||||||
|
std::visit(overloaded{
|
||||||
|
[&](TexturePackDisableAction& to_disable) {
|
||||||
|
enabled_texture_packs.erase(to_disable.path);
|
||||||
|
packs_disabled = true;
|
||||||
|
},
|
||||||
|
[&](TexturePackEnableAction& to_enable) {
|
||||||
|
enabled_texture_packs.insert(to_enable.path);
|
||||||
|
// Load the pack now if no packs have been disabled.
|
||||||
|
if (!packs_disabled) {
|
||||||
|
app->textureCache->loadReplacementDirectory(to_enable.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, cur_action);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If any packs were disabled, unload all packs and load all the active ones.
|
||||||
|
if (packs_disabled) {
|
||||||
|
app->textureCache->clearReplacementDirectories();
|
||||||
|
for (const std::filesystem::path& cur_pack_path : enabled_texture_packs) {
|
||||||
|
app->textureCache->loadReplacementDirectory(cur_pack_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
app->state->rsp->reset();
|
app->state->rsp->reset();
|
||||||
app->interpreter->loadUCodeGBI(task->t.ucode & 0x3FFFFFF, task->t.ucode_data & 0x3FFFFFF, true);
|
app->interpreter->loadUCodeGBI(task->t.ucode & 0x3FFFFFF, task->t.ucode_data & 0x3FFFFFF, true);
|
||||||
app->processDisplayLists(app->core.RDRAM, task->t.data_ptr & 0x3FFFFFF, 0, true);
|
app->processDisplayLists(app->core.RDRAM, task->t.data_ptr & 0x3FFFFFF, 0, true);
|
||||||
|
@ -376,3 +422,11 @@ bool zelda64::renderer::RT64SamplePositionsSupported() {
|
||||||
bool zelda64::renderer::RT64HighPrecisionFBEnabled() {
|
bool zelda64::renderer::RT64HighPrecisionFBEnabled() {
|
||||||
return high_precision_fb_enabled;
|
return high_precision_fb_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void zelda64::renderer::enable_texture_pack(const recomp::mods::ModHandle& mod) {
|
||||||
|
texture_pack_action_queue.enqueue(TexturePackEnableAction{mod.manifest.mod_root_path});
|
||||||
|
}
|
||||||
|
|
||||||
|
void zelda64::renderer::disable_texture_pack(const recomp::mods::ModHandle& mod) {
|
||||||
|
texture_pack_action_queue.enqueue(TexturePackDisableAction{mod.manifest.mod_root_path});
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef __APPLE__
|
||||||
|
|
||||||
|
#include "zelda_support.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
void zelda64::dispatch_on_main_thread(std::function<void()> func) {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "zelda_support.h"
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
void zelda64::dispatch_on_main_thread(std::function<void()> func) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
func();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* zelda64::get_bundle_resource_directory() {
|
||||||
|
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
|
||||||
|
return strdup([bundlePath UTF8String]);
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
#include "recomp_input.h"
|
#include "recomp_input.h"
|
||||||
#include "zelda_sound.h"
|
#include "zelda_sound.h"
|
||||||
#include "zelda_config.h"
|
#include "zelda_config.h"
|
||||||
|
#include "zelda_support.h"
|
||||||
#include "zelda_debug.h"
|
#include "zelda_debug.h"
|
||||||
#include "zelda_render.h"
|
#include "zelda_render.h"
|
||||||
#include "promptfont.h"
|
#include "promptfont.h"
|
||||||
|
@ -519,6 +520,11 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
Rml::ElementDocument* load_document(Rml::Context* context) override {
|
Rml::ElementDocument* load_document(Rml::Context* context) override {
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
const Rml::String asset = "/assets/config_menu.rml";
|
||||||
|
return context->LoadDocument(zelda64::get_bundle_resource_directory() + asset);
|
||||||
|
#endif
|
||||||
|
|
||||||
return context->LoadDocument("assets/config_menu.rml");
|
return context->LoadDocument("assets/config_menu.rml");
|
||||||
}
|
}
|
||||||
void register_events(recompui::UiEventListenerInstancer& listener) override {
|
void register_events(recompui::UiEventListenerInstancer& listener) override {
|
||||||
|
@ -725,7 +731,7 @@ public:
|
||||||
throw std::runtime_error("Failed to make RmlUi data model for the controls config menu");
|
throw std::runtime_error("Failed to make RmlUi data model for the controls config menu");
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.BindFunc("input_count", [](Rml::Variant& out) { out = recomp::get_num_inputs(); } );
|
constructor.BindFunc("input_count", [](Rml::Variant& out) { out = static_cast<uint64_t>(recomp::get_num_inputs()); } );
|
||||||
constructor.BindFunc("input_device_is_keyboard", [](Rml::Variant& out) { out = cur_device == recomp::InputDevice::Keyboard; } );
|
constructor.BindFunc("input_device_is_keyboard", [](Rml::Variant& out) { out = cur_device == recomp::InputDevice::Keyboard; } );
|
||||||
|
|
||||||
constructor.RegisterTransformFunc("get_input_name", [](const Rml::VariantList& inputs) {
|
constructor.RegisterTransformFunc("get_input_name", [](const Rml::VariantList& inputs) {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
#include "recomp_ui.h"
|
#include "recomp_ui.h"
|
||||||
#include "zelda_config.h"
|
#include "zelda_config.h"
|
||||||
|
#include "zelda_support.h"
|
||||||
#include "librecomp/game.hpp"
|
#include "librecomp/game.hpp"
|
||||||
#include "ultramodern/ultramodern.hpp"
|
#include "ultramodern/ultramodern.hpp"
|
||||||
#include "RmlUi/Core.h"
|
#include "RmlUi/Core.h"
|
||||||
#include "nfd.h"
|
#include "nfd.h"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
std::string version_number = "v1.1.1";
|
static std::string version_string;
|
||||||
|
|
||||||
Rml::DataModelHandle model_handle;
|
Rml::DataModelHandle model_handle;
|
||||||
bool mm_rom_valid = false;
|
bool mm_rom_valid = false;
|
||||||
|
@ -15,6 +16,7 @@ extern std::vector<recomp::GameEntry> supported_games;
|
||||||
|
|
||||||
void select_rom() {
|
void select_rom() {
|
||||||
nfdnchar_t* native_path = nullptr;
|
nfdnchar_t* native_path = nullptr;
|
||||||
|
zelda64::dispatch_on_main_thread([&native_path] {
|
||||||
nfdresult_t result = NFD_OpenDialogN(&native_path, nullptr, 0, nullptr);
|
nfdresult_t result = NFD_OpenDialogN(&native_path, nullptr, 0, nullptr);
|
||||||
|
|
||||||
if (result == NFD_OKAY) {
|
if (result == NFD_OKAY) {
|
||||||
|
@ -50,6 +52,7 @@ void select_rom() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class LauncherMenu : public recompui::MenuController {
|
class LauncherMenu : public recompui::MenuController {
|
||||||
|
@ -61,6 +64,11 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
Rml::ElementDocument* load_document(Rml::Context* context) override {
|
Rml::ElementDocument* load_document(Rml::Context* context) override {
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
const Rml::String asset = "/assets/launcher.rml";
|
||||||
|
return context->LoadDocument(zelda64::get_bundle_resource_directory() + asset);
|
||||||
|
#endif
|
||||||
|
|
||||||
return context->LoadDocument("assets/launcher.rml");
|
return context->LoadDocument("assets/launcher.rml");
|
||||||
}
|
}
|
||||||
void register_events(recompui::UiEventListenerInstancer& listener) override {
|
void register_events(recompui::UiEventListenerInstancer& listener) override {
|
||||||
|
@ -103,7 +111,9 @@ public:
|
||||||
Rml::DataModelConstructor constructor = context->CreateDataModel("launcher_model");
|
Rml::DataModelConstructor constructor = context->CreateDataModel("launcher_model");
|
||||||
|
|
||||||
constructor.Bind("mm_rom_valid", &mm_rom_valid);
|
constructor.Bind("mm_rom_valid", &mm_rom_valid);
|
||||||
constructor.Bind("version_number", &version_number);
|
|
||||||
|
version_string = recomp::get_project_version().to_string();
|
||||||
|
constructor.Bind("version_number", &version_string);
|
||||||
|
|
||||||
model_handle = constructor.GetModelHandle();
|
model_handle = constructor.GetModelHandle();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "librecomp/game.hpp"
|
#include "librecomp/game.hpp"
|
||||||
#include "zelda_config.h"
|
#include "zelda_config.h"
|
||||||
#include "ui_rml_hacks.hpp"
|
#include "ui_rml_hacks.hpp"
|
||||||
|
#include "zelda_support.h"
|
||||||
|
|
||||||
#include "concurrentqueue.h"
|
#include "concurrentqueue.h"
|
||||||
|
|
||||||
|
@ -1144,8 +1145,6 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
||||||
Rml::Debugger::Initialise(ui_context->rml.context);
|
Rml::Debugger::Initialise(ui_context->rml.context);
|
||||||
|
|
||||||
{
|
{
|
||||||
const Rml::String directory = "assets/";
|
|
||||||
|
|
||||||
struct FontFace {
|
struct FontFace {
|
||||||
const char* filename;
|
const char* filename;
|
||||||
bool fallback_face;
|
bool fallback_face;
|
||||||
|
@ -1162,7 +1161,13 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const FontFace& face : font_faces) {
|
for (const FontFace& face : font_faces) {
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
const Rml::String directory = "/assets/";
|
||||||
|
Rml::LoadFontFace(zelda64::get_bundle_resource_directory() + directory + face.filename, face.fallback_face);
|
||||||
|
#else
|
||||||
|
const Rml::String directory = "assets/";
|
||||||
Rml::LoadFontFace(directory + face.filename, face.fallback_face);
|
Rml::LoadFontFace(directory + face.filename, face.fallback_face);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1287,6 +1292,12 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
||||||
static recompui::Menu prev_menu = recompui::Menu::None;
|
static recompui::Menu prev_menu = recompui::Menu::None;
|
||||||
recompui::Menu cur_menu = open_menu.load();
|
recompui::Menu cur_menu = open_menu.load();
|
||||||
|
|
||||||
|
// Return to the launcher if no menu is open and the game isn't started.
|
||||||
|
if (cur_menu == recompui::Menu::None && !ultramodern::is_game_started()) {
|
||||||
|
cur_menu = recompui::Menu::Launcher;
|
||||||
|
recompui::set_current_menu(cur_menu);
|
||||||
|
}
|
||||||
|
|
||||||
if (reload_sheets) {
|
if (reload_sheets) {
|
||||||
ui_context->rml.load_documents();
|
ui_context->rml.load_documents();
|
||||||
prev_menu = recompui::Menu::None;
|
prev_menu = recompui::Menu::None;
|
||||||
|
@ -1500,6 +1511,9 @@ recompui::Menu recompui::get_current_menu() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void recompui::message_box(const char* msg) {
|
void recompui::message_box(const char* msg) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, zelda64::program_name.data(), msg, nullptr);
|
std::string message(msg);
|
||||||
|
zelda64::dispatch_on_main_thread([message] {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, zelda64::program_name.data(), message.c_str(), nullptr);
|
||||||
|
});
|
||||||
printf("[ERROR] %s\n", msg);
|
printf("[ERROR] %s\n", msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ entrypoint = 0x80080000
|
||||||
# Paths are relative to the location of this config file.
|
# Paths are relative to the location of this config file.
|
||||||
output_func_path = "RecompiledFuncs"
|
output_func_path = "RecompiledFuncs"
|
||||||
relocatable_sections_path = "overlays.us.rev1.txt"
|
relocatable_sections_path = "overlays.us.rev1.txt"
|
||||||
|
# elf_path = "mm.us.rev1.rom_uncompressed.elf"
|
||||||
symbols_file_path = "Zelda64RecompSyms/mm.us.rev1.syms.toml"
|
symbols_file_path = "Zelda64RecompSyms/mm.us.rev1.syms.toml"
|
||||||
rom_file_path = "mm.us.rev1.rom_uncompressed.z64"
|
rom_file_path = "mm.us.rev1.rom_uncompressed.z64"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue