mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp.git
synced 2025-03-30 13:20:10 +00:00
Add macOS Support (#537)
This commit is contained in:
parent
91db87632c
commit
25e7b31228
26
.github/macos/Info.plist.in
vendored
Normal file
26
.github/macos/Info.plist.in
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?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>GCSupportsGameMode</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
87
.github/macos/apple_bundle.cmake
vendored
Normal file
87
.github/macos/apple_bundle.cmake
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
# Define the path to the entitlements file
|
||||
set(ENTITLEMENTS_FILE ${CMAKE_SOURCE_DIR}/.github/macos/entitlements.plist)
|
||||
|
||||
# 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
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${ENTITLEMENTS_FILE}
|
||||
)
|
||||
|
||||
# Create icon files for macOS bundle
|
||||
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 .)
|
||||
|
||||
# Ensure the entitlements file exists
|
||||
if(NOT EXISTS ${ENTITLEMENTS_FILE})
|
||||
message(FATAL_ERROR "Entitlements file not found at ${ENTITLEMENTS_FILE}")
|
||||
endif()
|
||||
|
||||
# Post-build steps for macOS bundle
|
||||
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
|
||||
# Copy and fix frameworks first
|
||||
COMMAND ${CMAKE_COMMAND} -D CMAKE_BUILD_TYPE=$<CONFIG> -D CMAKE_GENERATOR=${CMAKE_GENERATOR} -P ${CMAKE_SOURCE_DIR}/.github/macos/fixup_bundle.cmake
|
||||
|
||||
# Copy all resources
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets ${CMAKE_BINARY_DIR}/temp_assets
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/temp_assets/scss
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/temp_assets $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/assets
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/temp_assets
|
||||
|
||||
# Copy controller database
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/gamecontrollerdb.txt $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/
|
||||
|
||||
# Set RPATH
|
||||
COMMAND install_name_tool -add_rpath "@executable_path/../Frameworks/" $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/MacOS/Zelda64Recompiled
|
||||
|
||||
# Sign the bundle
|
||||
COMMAND codesign --verbose=4 --options=runtime --no-strict --sign - --entitlements ${ENTITLEMENTS_FILE} --deep --force $<TARGET_BUNDLE_DIR:Zelda64Recompiled>
|
||||
|
||||
COMMENT "Performing post-build steps for macOS bundle"
|
||||
VERBATIM
|
||||
)
|
14
.github/macos/entitlements.plist
vendored
Normal file
14
.github/macos/entitlements.plist
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?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>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-executable-page-protection</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
44
.github/macos/fixup_bundle.cmake
vendored
Normal file
44
.github/macos/fixup_bundle.cmake
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
include(BundleUtilities)
|
||||
|
||||
# Check for pkgx installation
|
||||
find_program(PKGX_EXECUTABLE pkgx)
|
||||
|
||||
# Xcode generator puts the build type in the build directory
|
||||
set(BUILD_PREFIX "")
|
||||
if (CMAKE_GENERATOR STREQUAL "Xcode")
|
||||
set(BUILD_PREFIX "${CMAKE_BUILD_TYPE}/")
|
||||
endif()
|
||||
|
||||
# Use generator expressions to get the absolute path to the bundle
|
||||
set(APPS "${BUILD_PREFIX}Zelda64Recompiled.app/Contents/MacOS/Zelda64Recompiled")
|
||||
|
||||
# Set up framework search paths
|
||||
set(DIRS "${BUILD_PREFIX}Zelda64Recompiled.app/Contents/Frameworks")
|
||||
|
||||
# Detect if we're using pkgx
|
||||
if(PKGX_EXECUTABLE)
|
||||
message(STATUS "pkgx detected, adding pkgx directories to framework search path")
|
||||
list(APPEND DIRS "$ENV{HOME}/.pkgx/")
|
||||
endif()
|
||||
|
||||
# Convert all paths to absolute paths
|
||||
file(REAL_PATH ${APPS} APPS)
|
||||
|
||||
set(RESOLVED_DIRS "")
|
||||
foreach(DIR IN LISTS DIRS)
|
||||
# Handle home directory expansion
|
||||
string(REPLACE "~" "$ENV{HOME}" DIR "${DIR}")
|
||||
# Convert to absolute path, but don't fail if directory doesn't exist
|
||||
if(EXISTS "${DIR}")
|
||||
file(REAL_PATH "${DIR}" RESOLVED_DIR)
|
||||
list(APPEND RESOLVED_DIRS "${RESOLVED_DIR}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Debug output
|
||||
message(STATUS "Bundle fixup paths:")
|
||||
message(STATUS " App: ${APPS}")
|
||||
message(STATUS " Search dirs: ${RESOLVED_DIRS}")
|
||||
|
||||
# Fix up the bundle
|
||||
fixup_bundle("${APPS}" "" "${RESOLVED_DIRS}")
|
73
.github/macos/ld64
vendored
Executable file
73
.github/macos/ld64
vendored
Executable file
@ -0,0 +1,73 @@
|
||||
#!/usr/bin/python3
|
||||
"""
|
||||
Custom ld64 wrapper for macOS
|
||||
|
||||
This script wraps the standard macOS linker (/usr/bin/ld) to modify executable memory
|
||||
protection flags in the resulting Mach-O binary. It works in three stages:
|
||||
|
||||
1. First, it passes through all arguments to the regular macOS linker to create the binary
|
||||
2. Then, it parses command line arguments to identify output file and segment protection flags
|
||||
3. Finally, it modifies the output binary's Mach-O headers to ensure segments (particularly __TEXT)
|
||||
have the maximum protection flags (rwx) we specify, even if the default macOS linker would restrict them
|
||||
|
||||
This is necessary because macOS restricts writable+executable memory by default,
|
||||
but certain applications need this capability for dynamic code generation or JIT compilation.
|
||||
|
||||
Usage: Same as the standard ld64 linker, with the added benefit that -segprot options
|
||||
will have their max_prot values properly preserved in the output binary.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
from itertools import takewhile
|
||||
from macholib import MachO, ptypes
|
||||
|
||||
def parse_rwx(text):
|
||||
return ('r' in text and 1) | ('w' in text and 2) | ('x' in text and 4)
|
||||
|
||||
def apply_maxprots(path, maxprots):
|
||||
mach = MachO.MachO(path)
|
||||
header = mach.headers[0]
|
||||
offset = ptypes.sizeof(header.mach_header)
|
||||
|
||||
for cload, ccmd, cdata in header.commands:
|
||||
if not hasattr(ccmd, 'segname'):
|
||||
break
|
||||
|
||||
if hasattr(ccmd.segname, 'to_str'):
|
||||
segname = ccmd.segname.to_str().decode('utf-8').strip('\0')
|
||||
else:
|
||||
segname = ccmd.segname.decode('utf-8').strip('\0')
|
||||
|
||||
if segname in maxprots and ccmd.maxprot != maxprots[segname]:
|
||||
fields = list(takewhile(lambda field: field[0] != 'maxprot', cload._fields_ + ccmd._fields_))
|
||||
index = offset + sum(ptypes.sizeof(typ) for _, typ in fields)
|
||||
|
||||
with open(path, 'r+b') as fh:
|
||||
fh.seek(index)
|
||||
fh.write(bytes([maxprots[segname]]))
|
||||
|
||||
offset += cload.cmdsize
|
||||
|
||||
try:
|
||||
subprocess.check_call(['/usr/bin/ld'] + sys.argv[1:])
|
||||
except subprocess.CalledProcessError as ex:
|
||||
sys.exit(ex.returncode)
|
||||
|
||||
output_file = 'a.out'
|
||||
segprots = {'__TEXT': parse_rwx('rwx')} # maxprot = rwx
|
||||
|
||||
i = 1
|
||||
while i < len(sys.argv):
|
||||
if sys.argv[i] == '-o' and i + 1 < len(sys.argv):
|
||||
output_file = sys.argv[i + 1]
|
||||
i += 2
|
||||
elif sys.argv[i] == '-segprot' and i + 3 < len(sys.argv):
|
||||
segment = sys.argv[i + 1]
|
||||
maxprot = sys.argv[i + 2]
|
||||
segprots[segment] = parse_rwx(maxprot)
|
||||
i += 4
|
||||
else:
|
||||
i += 1
|
||||
|
||||
apply_maxprots(output_file, segprots)
|
14
.github/macos/macports.yaml
vendored
Normal file
14
.github/macos/macports.yaml
vendored
Normal file
@ -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
|
77
.github/workflows/validate.yml
vendored
77
.github/workflows/validate.yml
vendored
@ -78,16 +78,16 @@ jobs:
|
||||
- name: Hotpatch DXC into RT64's contrib
|
||||
run: |
|
||||
# check if dxc was updated before we replace it, to detect changes
|
||||
echo ${{ inputs.DXC_CHECKSUM }} ./lib/rt64/src/contrib/dxc/bin/x64/dxc | sha256sum --status -c -
|
||||
echo ${{ inputs.DXC_CHECKSUM }} ./lib/rt64/src/contrib/dxc/bin/x64/dxc-linux | sha256sum --status -c -
|
||||
|
||||
cp -v /usr/local/lib/libdxcompiler.so ./lib/rt64/src/contrib/dxc/lib/x64/libdxcompiler.so
|
||||
cp -v /usr/local/bin/dxc ./lib/rt64/src/contrib/dxc/bin/x64/dxc
|
||||
cp -v /usr/local/bin/dxc ./lib/rt64/src/contrib/dxc/bin/x64/dxc-linux
|
||||
- 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_CXX_COMPILER=clang++-17 -DCMAKE_C_COMPILER=clang-17 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build -DPATCHES_C_COMPILER=clang-17 -DPATCHES_LD=ld.lld-17 -DPATCHES_OBJCOPY=llvm-objcopy-17
|
||||
cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=clang++-17 -DCMAKE_C_COMPILER=clang-17 -DCMAKE_MAKE_PROGRAM=ninja -G Ninja -S . -B cmake-build -DPATCHES_C_COMPILER=clang-17 -DPATCHES_LD=ld.lld-17
|
||||
cmake --build cmake-build --config ${{ matrix.type }} --target Zelda64Recompiled -j $(nproc)
|
||||
- name: Prepare Archive
|
||||
run: |
|
||||
@ -283,3 +283,74 @@ jobs:
|
||||
name: Zelda64Recompiled-PDB-${{ matrix.type }}
|
||||
path: |
|
||||
Zelda64Recompiled.pdb
|
||||
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: 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 -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)
|
||||
- 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
|
||||
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -2,6 +2,7 @@
|
||||
.vscode/settings.json
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/tasks.json
|
||||
|
||||
# Input elf and rom files
|
||||
*.elf
|
||||
@ -62,3 +63,9 @@ RSPRecomp
|
||||
|
||||
# Controller mappings file
|
||||
gamecontrollerdb.txt
|
||||
|
||||
# Cmake build directory
|
||||
.cache
|
||||
.idea
|
||||
build-*
|
||||
cmake-build-*
|
@ -1,5 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(Zelda64Recompiled)
|
||||
|
||||
if (APPLE)
|
||||
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_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
@ -15,6 +20,10 @@ if (WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
enable_language(OBJC OBJCXX)
|
||||
endif()
|
||||
|
||||
# Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24:
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
|
||||
cmake_policy(SET CMP0135 NEW)
|
||||
@ -107,7 +116,7 @@ add_custom_target(PatchesBin
|
||||
|
||||
# Generate patches_bin.c from patches.bin
|
||||
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/RecompiledPatches/patches_bin.c
|
||||
COMMAND file_to_c ${CMAKE_SOURCE_DIR}/patches/patches.bin mm_patches_bin ${CMAKE_SOURCE_DIR}/RecompiledPatches/patches_bin.c ${CMAKE_SOURCE_DIR}/RecompiledPatches/patches_bin.h
|
||||
COMMAND file_to_c ${CMAKE_SOURCE_DIR}/patches/patches.bin mm_patches_bin ${CMAKE_SOURCE_DIR}/RecompiledPatches/patches_bin.c ${CMAKE_SOURCE_DIR}/RecompiledPatches/patches_bin.h
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/patches/patches.bin
|
||||
)
|
||||
|
||||
@ -139,6 +148,7 @@ add_dependencies(Zelda64Recompiled DownloadGameControllerDB)
|
||||
|
||||
set (SOURCES
|
||||
${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_patches.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/main/rt64_render_context.cpp
|
||||
@ -164,6 +174,10 @@ set (SOURCES
|
||||
${CMAKE_SOURCE_DIR}/lib/RmlUi/Backends/RmlUi_Platform_SDL.cpp
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND SOURCES ${CMAKE_SOURCE_DIR}/src/main/support_apple.mm)
|
||||
endif()
|
||||
|
||||
target_include_directories(Zelda64Recompiled PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/lib/N64ModernRuntime/N64Recomp/include
|
||||
@ -199,6 +213,12 @@ 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)
|
||||
elseif (APPLE)
|
||||
# Use a wrapper around ld64 that respects segprot's `max_prot` value in order
|
||||
# to make our executable memory writable (required for mod function patching)
|
||||
target_link_options(Zelda64Recompiled PRIVATE
|
||||
"-fuse-ld=${CMAKE_SOURCE_DIR}/.github/macos/ld64"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
@ -241,6 +261,20 @@ if (WIN32)
|
||||
)
|
||||
|
||||
target_sources(Zelda64Recompiled PRIVATE ${CMAKE_SOURCE_DIR}/icons/app.rc)
|
||||
target_link_libraries(Zelda64Recompiled PRIVATE SDL2)
|
||||
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 SDL2::SDL2)
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/.github/macos/apple_bundle.cmake)
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
@ -251,7 +285,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
|
||||
# Generate icon_bytes.c from the app icon PNG.
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icon_bytes.c ${CMAKE_CURRENT_BINARY_DIR}/icon_bytes.h
|
||||
COMMAND file_to_c ${CMAKE_SOURCE_DIR}/icons/512.png icon_bytes ${CMAKE_CURRENT_BINARY_DIR}/icon_bytes.c ${CMAKE_CURRENT_BINARY_DIR}/icon_bytes.h
|
||||
COMMAND file_to_c ${CMAKE_SOURCE_DIR}/icons/512.png icon_bytes ${CMAKE_CURRENT_BINARY_DIR}/icon_bytes.c ${CMAKE_CURRENT_BINARY_DIR}/icon_bytes.h
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/icons/512.png
|
||||
)
|
||||
target_sources(Zelda64Recompiled PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/icon_bytes.c)
|
||||
@ -276,7 +310,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
message(STATUS "FREETYPE_LIBRARIES = ${FREETYPE_LIBRARIES}")
|
||||
|
||||
include_directories(${FREETYPE_LIBRARIES})
|
||||
target_link_libraries(Zelda64Recompiled PRIVATE ${FREETYPE_LIBRARIES})
|
||||
target_link_libraries(Zelda64Recompiled PRIVATE ${FREETYPE_LIBRARIES} SDL2::SDL2)
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
@ -288,7 +322,6 @@ endif()
|
||||
target_link_libraries(Zelda64Recompiled PRIVATE
|
||||
PatchesLib
|
||||
RecompiledFuncs
|
||||
SDL2
|
||||
librecomp
|
||||
ultramodern
|
||||
rt64
|
||||
@ -316,9 +349,14 @@ else()
|
||||
if (APPLE)
|
||||
# Apple's binary is universal, so it'll work on both x86_64 and arm64
|
||||
set (DXC "DYLD_LIBRARY_PATH=${PROJECT_SOURCE_DIR}/lib/rt64/src/contrib/dxc/lib/arm64" "${PROJECT_SOURCE_DIR}/lib/rt64/src/contrib/dxc/bin/arm64/dxc-macos")
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
|
||||
set(SPIRVCROSS "DYLD_LIBRARY_PATH=${PROJECT_SOURCE_DIR}/lib/rt64/src/contrib/spirv-cross/lib/x64" "${PROJECT_SOURCE_DIR}/lib/rt64//src/contrib/spirv-cross/bin/x64/spirv-cross")
|
||||
else()
|
||||
set(SPIRVCROSS "DYLD_LIBRARY_PATH=${PROJECT_SOURCE_DIR}/lib/rt64/src/contrib/spirv-cross/lib/arm64" "${PROJECT_SOURCE_DIR}/lib/rt64//src/contrib/spirv-cross/bin/x64/spirv-cross")
|
||||
endif()
|
||||
else()
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
|
||||
set (DXC "LD_LIBRARY_PATH=${PROJECT_SOURCE_DIR}/lib/rt64/src/contrib/dxc/lib/x64" "${PROJECT_SOURCE_DIR}/lib/rt64/src/contrib/dxc/bin/x64/dxc")
|
||||
set (DXC "LD_LIBRARY_PATH=${PROJECT_SOURCE_DIR}/lib/rt64/src/contrib/dxc/lib/x64" "${PROJECT_SOURCE_DIR}/lib/rt64/src/contrib/dxc/bin/x64/dxc-linux")
|
||||
else()
|
||||
set (DXC "LD_LIBRARY_PATH=${PROJECT_SOURCE_DIR}/lib/rt64/src/contrib/dxc/lib/arm64" "${PROJECT_SOURCE_DIR}/lib/rt64/src/contrib/dxc/bin/arm64/dxc-linux")
|
||||
endif()
|
||||
@ -331,4 +369,3 @@ build_pixel_shader(Zelda64Recompiled "shaders/InterfacePS.hlsl" "shaders/Interfa
|
||||
target_sources(Zelda64Recompiled PRIVATE ${SOURCES})
|
||||
|
||||
set_property(TARGET Zelda64Recompiled PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef __ZELDA_RENDER_H__
|
||||
#define __ZELDA_RENDER_H__
|
||||
|
||||
#include <unordered_set>
|
||||
#include <set>
|
||||
#include <filesystem>
|
||||
|
||||
#include "common/rt64_user_configuration.h"
|
||||
@ -32,7 +32,7 @@ namespace zelda64 {
|
||||
|
||||
protected:
|
||||
std::unique_ptr<RT64::Application> app;
|
||||
std::unordered_set<std::filesystem::path> enabled_texture_packs;
|
||||
std::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);
|
||||
|
19
include/zelda_support.h
Normal file
19
include/zelda_support.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef __ZELDA_SUPPORT_H__
|
||||
#define __ZELDA_SUPPORT_H__
|
||||
|
||||
#include <functional>
|
||||
#include <filesystem>
|
||||
|
||||
namespace zelda64 {
|
||||
std::filesystem::path get_asset_path(const char* asset);
|
||||
void open_file_dialog(std::function<void(bool success, const std::filesystem::path& path)> callback);
|
||||
void show_error_message_box(const char *title, const char *message);
|
||||
|
||||
// Apple specific methods that usually require Objective-C. Implemented in support_apple.mm.
|
||||
#ifdef __APPLE__
|
||||
void dispatch_on_ui_thread(std::function<void()> func);
|
||||
const char* get_bundle_resource_directory();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
@ -1 +1 @@
|
||||
Subproject commit 0afeb089a55cb391c24352f23b7683ab3c2ca854
|
||||
Subproject commit ec56fb39b0d295d9636cb60e252088d7b23c7ac9
|
2
lib/rt64
2
lib/rt64
@ -1 +1 @@
|
||||
Subproject commit 0ca92eeb6c2f58ce3581c65f87f7261b8ac0fea0
|
||||
Subproject commit 8efb6cc8168e746fb22d08c2dd766b2a176e1a51
|
@ -13,6 +13,8 @@
|
||||
#elif defined(__linux__)
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include "apple/rt64_apple.h"
|
||||
#endif
|
||||
|
||||
constexpr std::u8string_view general_filename = u8"general.json";
|
||||
@ -71,7 +73,7 @@ T from_or_default(const json& j, const std::string& key, T default_value) {
|
||||
else {
|
||||
ret = default_value;
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -129,7 +131,7 @@ namespace recomp {
|
||||
}
|
||||
|
||||
std::filesystem::path zelda64::get_app_folder_path() {
|
||||
// directly check for portable.txt (windows and native linux binary)
|
||||
// directly check for portable.txt (windows and native linux binary)
|
||||
if (std::filesystem::exists("portable.txt")) {
|
||||
return std::filesystem::current_path();
|
||||
}
|
||||
@ -145,8 +147,8 @@ std::filesystem::path zelda64::get_app_folder_path() {
|
||||
}
|
||||
|
||||
CoTaskMemFree(known_path);
|
||||
#elif defined(__linux__)
|
||||
// check for APP_FOLDER_PATH env var used by AppImage
|
||||
#elif defined(__linux__) || defined(__APPLE__)
|
||||
// check for APP_FOLDER_PATH env var
|
||||
if (getenv("APP_FOLDER_PATH") != nullptr) {
|
||||
return std::filesystem::path{getenv("APP_FOLDER_PATH")};
|
||||
}
|
||||
@ -154,7 +156,11 @@ std::filesystem::path zelda64::get_app_folder_path() {
|
||||
const char *homedir;
|
||||
|
||||
if ((homedir = getenv("HOME")) == nullptr) {
|
||||
#if defined(__linux__)
|
||||
homedir = getpwuid(getuid())->pw_dir;
|
||||
#elif defined(__APPLE__)
|
||||
homedir = GetHomeDirectory();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (homedir != nullptr) {
|
||||
@ -206,7 +212,7 @@ bool save_json_with_backups(const std::filesystem::path& path, const nlohmann::j
|
||||
return recomp::finalize_output_file_with_backup(path);
|
||||
}
|
||||
|
||||
bool save_general_config(const std::filesystem::path& path) {
|
||||
bool save_general_config(const std::filesystem::path& path) {
|
||||
nlohmann::json config_json{};
|
||||
|
||||
zelda64::to_json(config_json["targeting_mode"], zelda64::get_targeting_mode());
|
||||
@ -220,7 +226,7 @@ bool save_general_config(const std::filesystem::path& path) {
|
||||
config_json["analog_cam_mode"] = zelda64::get_analog_cam_mode();
|
||||
config_json["analog_camera_invert_mode"] = zelda64::get_analog_camera_invert_mode();
|
||||
config_json["debug_mode"] = zelda64::get_debug_mode_enabled();
|
||||
|
||||
|
||||
return save_json_with_backups(path, config_json);
|
||||
}
|
||||
|
||||
@ -438,7 +444,7 @@ bool save_sound_config(const std::filesystem::path& path) {
|
||||
config_json["main_volume"] = zelda64::get_main_volume();
|
||||
config_json["bgm_volume"] = zelda64::get_bgm_volume();
|
||||
config_json["low_health_beeps"] = zelda64::get_low_health_beeps_enabled();
|
||||
|
||||
|
||||
return save_json_with_backups(path, config_json);
|
||||
}
|
||||
|
||||
@ -500,7 +506,7 @@ void zelda64::save_config() {
|
||||
}
|
||||
|
||||
std::filesystem::create_directories(recomp_dir);
|
||||
|
||||
|
||||
// TODO error handling for failing to save config files.
|
||||
|
||||
save_general_config(recomp_dir / general_filename);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "zelda_config.h"
|
||||
#include "zelda_sound.h"
|
||||
#include "zelda_render.h"
|
||||
#include "zelda_support.h"
|
||||
#include "zelda_game.h"
|
||||
#include "ovl_patches.hpp"
|
||||
#include "librecomp/game.hpp"
|
||||
@ -51,7 +52,8 @@ void exit_error(const char* str, Ts ...args) {
|
||||
// TODO pop up an error
|
||||
((void)fprintf(stderr, str, args), ...);
|
||||
assert(false);
|
||||
std::quick_exit(EXIT_FAILURE);
|
||||
|
||||
ultramodern::error_handling::quick_exit(__FILE__, __LINE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
ultramodern::gfx_callbacks_t::gfx_data_t create_gfx() {
|
||||
@ -125,7 +127,9 @@ SDL_Window* window;
|
||||
ultramodern::renderer::WindowHandle create_window(ultramodern::gfx_callbacks_t::gfx_data_t) {
|
||||
uint32_t flags = SDL_WINDOW_RESIZABLE;
|
||||
|
||||
#if defined(RT64_SDL_WINDOW_VULKAN)
|
||||
#if defined(__APPLE__)
|
||||
flags |= SDL_WINDOW_METAL;
|
||||
#elif defined(RT64_SDL_WINDOW_VULKAN)
|
||||
flags |= SDL_WINDOW_VULKAN;
|
||||
#endif
|
||||
|
||||
@ -151,6 +155,9 @@ ultramodern::renderer::WindowHandle create_window(ultramodern::gfx_callbacks_t::
|
||||
return ultramodern::renderer::WindowHandle{ wmInfo.info.win.window, GetCurrentThreadId() };
|
||||
#elif defined(__linux__) || defined(__ANDROID__)
|
||||
return ultramodern::renderer::WindowHandle{ window };
|
||||
#elif defined(__APPLE__)
|
||||
SDL_MetalView view = SDL_Metal_CreateView(window);
|
||||
return ultramodern::renderer::WindowHandle{ wmInfo.info.cocoa.window, SDL_Metal_GetLayer(view) };
|
||||
#else
|
||||
static_assert(false && "Unimplemented");
|
||||
#endif
|
||||
|
@ -263,6 +263,9 @@ zelda64::renderer::RT64Context::RT64Context(uint8_t* rdram, ultramodern::rendere
|
||||
case ultramodern::renderer::GraphicsApi::Vulkan:
|
||||
app->userConfig.graphicsAPI = RT64::UserConfiguration::GraphicsAPI::Vulkan;
|
||||
break;
|
||||
case ultramodern::renderer::GraphicsApi::Metal:
|
||||
app->userConfig.graphicsAPI = RT64::UserConfiguration::GraphicsAPI::Metal;
|
||||
break;
|
||||
default:
|
||||
case ultramodern::renderer::GraphicsApi::Auto:
|
||||
// Don't override if auto is selected.
|
||||
|
58
src/main/support.cpp
Normal file
58
src/main/support.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
#include "zelda_support.h"
|
||||
#include <SDL.h>
|
||||
#include "nfd.h"
|
||||
#include "RmlUi/Core.h"
|
||||
|
||||
namespace zelda64 {
|
||||
// MARK: - Internal Helpers
|
||||
void perform_file_dialog_operation(const std::function<void(bool, const std::filesystem::path&)>& callback) {
|
||||
nfdnchar_t* native_path = nullptr;
|
||||
nfdresult_t result = NFD_OpenDialogN(&native_path, nullptr, 0, nullptr);
|
||||
|
||||
bool success = (result == NFD_OKAY);
|
||||
std::filesystem::path path;
|
||||
|
||||
if (success) {
|
||||
path = std::filesystem::path{native_path};
|
||||
NFD_FreePathN(native_path);
|
||||
}
|
||||
|
||||
callback(success, path);
|
||||
}
|
||||
|
||||
// MARK: - Public API
|
||||
|
||||
std::filesystem::path get_asset_path(const char* asset) {
|
||||
std::filesystem::path base_path = "";
|
||||
#if defined(__APPLE__)
|
||||
const char* resource_dir = get_bundle_resource_directory();
|
||||
base_path = resource_dir;
|
||||
free((void*)resource_dir);
|
||||
#endif
|
||||
|
||||
return base_path / "assets" / asset;
|
||||
}
|
||||
|
||||
void open_file_dialog(std::function<void(bool success, const std::filesystem::path& path)> callback) {
|
||||
#ifdef __APPLE__
|
||||
dispatch_on_ui_thread([callback]() {
|
||||
perform_file_dialog_operation(callback);
|
||||
});
|
||||
#else
|
||||
perform_file_dialog_operation(callback);
|
||||
#endif
|
||||
}
|
||||
|
||||
void show_error_message_box(const char *title, const char *message) {
|
||||
#ifdef __APPLE__
|
||||
std::string title_copy(title);
|
||||
std::string message_copy(message);
|
||||
|
||||
dispatch_on_ui_thread([title_copy, message_copy] {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title_copy.c_str(), message_copy.c_str(), nullptr);
|
||||
});
|
||||
#else
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, message, nullptr);
|
||||
#endif
|
||||
}
|
||||
}
|
54
src/main/support_apple.mm
Normal file
54
src/main/support_apple.mm
Normal file
@ -0,0 +1,54 @@
|
||||
#include "zelda_support.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
#include <SDL.h>
|
||||
#include "nfd.h"
|
||||
|
||||
namespace zelda64 {
|
||||
void dispatch_on_ui_thread(std::function<void()> func) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
func();
|
||||
});
|
||||
}
|
||||
|
||||
const char* get_bundle_resource_directory() {
|
||||
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
|
||||
return strdup([bundlePath UTF8String]);
|
||||
}
|
||||
}
|
||||
|
||||
// Used to swizzle the updateDrawableSize method in SDL_cocoametalview to not
|
||||
// automatically resize the underlying CAMetalLayer when the window size changes.
|
||||
static void MySwizzleSDLMetalView(void) {
|
||||
Class cls = objc_getClass("SDL_cocoametalview");
|
||||
if (!cls) {
|
||||
// Probably means SDL is using a different name, or the symbol is still hidden.
|
||||
return;
|
||||
}
|
||||
|
||||
SEL originalSelector = sel_registerName("updateDrawableSize");
|
||||
SEL swizzledSelector = sel_registerName("my_updateDrawableSize");
|
||||
|
||||
Method originalMethod = class_getInstanceMethod(cls, originalSelector);
|
||||
if (!originalMethod) {
|
||||
// The method might not exist or might get inlined in some SDL builds.
|
||||
return;
|
||||
}
|
||||
|
||||
// Implementation of our replacement method
|
||||
IMP swizzledIMP = imp_implementationWithBlock(^void(id selfObj) {
|
||||
// (no-op)
|
||||
});
|
||||
|
||||
// Swizzle method
|
||||
class_addMethod(cls, swizzledSelector, swizzledIMP, method_getTypeEncoding(originalMethod));
|
||||
Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
static void PatchSDLMetalViewConstructor() {
|
||||
// This runs as soon as the dynamic library/executable is loaded, before main().
|
||||
MySwizzleSDLMetalView();
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
#include "zelda_config.h"
|
||||
#include "zelda_debug.h"
|
||||
#include "zelda_render.h"
|
||||
#include "zelda_support.h"
|
||||
#include "promptfont.h"
|
||||
#include "ultramodern/config.hpp"
|
||||
#include "ultramodern/ultramodern.hpp"
|
||||
@ -519,7 +520,8 @@ public:
|
||||
|
||||
}
|
||||
Rml::ElementDocument* load_document(Rml::Context* context) override {
|
||||
return context->LoadDocument("assets/config_menu.rml");
|
||||
const std::filesystem::path asset = zelda64::get_asset_path("config_menu.rml");
|
||||
return context->LoadDocument(asset.string());
|
||||
}
|
||||
void register_events(recompui::UiEventListenerInstancer& listener) override {
|
||||
recompui::register_event(listener, "apply_options",
|
||||
@ -725,7 +727,7 @@ public:
|
||||
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.RegisterTransformFunc("get_input_name", [](const Rml::VariantList& inputs) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "recomp_ui.h"
|
||||
#include "zelda_config.h"
|
||||
#include "zelda_support.h"
|
||||
#include "librecomp/game.hpp"
|
||||
#include "ultramodern/ultramodern.hpp"
|
||||
#include "RmlUi/Core.h"
|
||||
@ -15,41 +16,36 @@ extern std::vector<recomp::GameEntry> supported_games;
|
||||
|
||||
void select_rom() {
|
||||
nfdnchar_t* native_path = nullptr;
|
||||
nfdresult_t result = NFD_OpenDialogN(&native_path, nullptr, 0, nullptr);
|
||||
|
||||
if (result == NFD_OKAY) {
|
||||
std::filesystem::path path{native_path};
|
||||
|
||||
NFD_FreePathN(native_path);
|
||||
native_path = nullptr;
|
||||
|
||||
recomp::RomValidationError rom_error = recomp::select_rom(path, supported_games[0].game_id);
|
||||
switch (rom_error) {
|
||||
case recomp::RomValidationError::Good:
|
||||
mm_rom_valid = true;
|
||||
model_handle.DirtyVariable("mm_rom_valid");
|
||||
break;
|
||||
case recomp::RomValidationError::FailedToOpen:
|
||||
recompui::message_box("Failed to open ROM file.");
|
||||
break;
|
||||
case recomp::RomValidationError::NotARom:
|
||||
recompui::message_box("This is not a valid ROM file.");
|
||||
break;
|
||||
case recomp::RomValidationError::IncorrectRom:
|
||||
recompui::message_box("This ROM is not the correct game.");
|
||||
break;
|
||||
case recomp::RomValidationError::NotYet:
|
||||
recompui::message_box("This game isn't supported yet.");
|
||||
break;
|
||||
case recomp::RomValidationError::IncorrectVersion:
|
||||
recompui::message_box(
|
||||
"This ROM is the correct game, but the wrong version.\nThis project requires the NTSC-U N64 version of the game.");
|
||||
break;
|
||||
case recomp::RomValidationError::OtherError:
|
||||
recompui::message_box("An unknown error has occurred.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
zelda64::open_file_dialog([](bool success, const std::filesystem::path& path) {
|
||||
if (success) {
|
||||
recomp::RomValidationError rom_error = recomp::select_rom(path, supported_games[0].game_id);
|
||||
switch (rom_error) {
|
||||
case recomp::RomValidationError::Good:
|
||||
mm_rom_valid = true;
|
||||
model_handle.DirtyVariable("mm_rom_valid");
|
||||
break;
|
||||
case recomp::RomValidationError::FailedToOpen:
|
||||
recompui::message_box("Failed to open ROM file.");
|
||||
break;
|
||||
case recomp::RomValidationError::NotARom:
|
||||
recompui::message_box("This is not a valid ROM file.");
|
||||
break;
|
||||
case recomp::RomValidationError::IncorrectRom:
|
||||
recompui::message_box("This ROM is not the correct game.");
|
||||
break;
|
||||
case recomp::RomValidationError::NotYet:
|
||||
recompui::message_box("This game isn't supported yet.");
|
||||
break;
|
||||
case recomp::RomValidationError::IncorrectVersion:
|
||||
recompui::message_box(
|
||||
"This ROM is the correct game, but the wrong version.\nThis project requires the NTSC-U N64 version of the game.");
|
||||
break;
|
||||
case recomp::RomValidationError::OtherError:
|
||||
recompui::message_box("An unknown error has occurred.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class LauncherMenu : public recompui::MenuController {
|
||||
@ -61,7 +57,8 @@ public:
|
||||
|
||||
}
|
||||
Rml::ElementDocument* load_document(Rml::Context* context) override {
|
||||
return context->LoadDocument("assets/launcher.rml");
|
||||
const std::filesystem::path asset = zelda64::get_asset_path("launcher.rml");
|
||||
return context->LoadDocument(asset.string());
|
||||
}
|
||||
void register_events(recompui::UiEventListenerInstancer& listener) override {
|
||||
recompui::register_event(listener, "select_rom",
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "recomp_input.h"
|
||||
#include "librecomp/game.hpp"
|
||||
#include "zelda_config.h"
|
||||
#include "zelda_support.h"
|
||||
#include "ui_rml_hacks.hpp"
|
||||
|
||||
#include "concurrentqueue.h"
|
||||
@ -34,6 +35,9 @@
|
||||
#ifdef _WIN32
|
||||
# include "InterfaceVS.hlsl.dxil.h"
|
||||
# include "InterfacePS.hlsl.dxil.h"
|
||||
#elif defined(__APPLE__)
|
||||
# include "InterfaceVS.hlsl.metal.h"
|
||||
# include "InterfacePS.hlsl.metal.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -43,6 +47,13 @@
|
||||
# define GET_SHADER_SIZE(name, format) \
|
||||
((format) == RT64::RenderShaderFormat::SPIRV ? std::size(name##BlobSPIRV) : \
|
||||
(format) == RT64::RenderShaderFormat::DXIL ? std::size(name##BlobDXIL) : 0)
|
||||
#elif defined(__APPLE__)
|
||||
# define GET_SHADER_BLOB(name, format) \
|
||||
((format) == RT64::RenderShaderFormat::SPIRV ? name##BlobSPIRV : \
|
||||
(format) == RT64::RenderShaderFormat::METAL ? name##BlobMSL : nullptr)
|
||||
# define GET_SHADER_SIZE(name, format) \
|
||||
((format) == RT64::RenderShaderFormat::SPIRV ? std::size(name##BlobSPIRV) : \
|
||||
(format) == RT64::RenderShaderFormat::METAL ? std::size(name##BlobMSL) : 0)
|
||||
#else
|
||||
# define GET_SHADER_BLOB(name, format) \
|
||||
((format) == RT64::RenderShaderFormat::SPIRV ? name##BlobSPIRV : nullptr)
|
||||
@ -1144,8 +1155,6 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
||||
Rml::Debugger::Initialise(ui_context->rml.context);
|
||||
|
||||
{
|
||||
const Rml::String directory = "assets/";
|
||||
|
||||
struct FontFace {
|
||||
const char* filename;
|
||||
bool fallback_face;
|
||||
@ -1162,7 +1171,8 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
||||
};
|
||||
|
||||
for (const FontFace& face : font_faces) {
|
||||
Rml::LoadFontFace(directory + face.filename, face.fallback_face);
|
||||
auto font = zelda64::get_asset_path(face.filename);
|
||||
Rml::LoadFontFace(font.string(), face.fallback_face);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user