mirror of
				https://github.com/Zelda64Recomp/Zelda64Recomp.git
				synced 2025-10-30 08:03:03 +00:00 
			
		
		
		
	Add macOS Support
This commit is contained in:
		
							parent
							
								
									91db87632c
								
							
						
					
					
						commit
						855ee68466
					
				
					 21 changed files with 594 additions and 65 deletions
				
			
		
							
								
								
									
										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) | ||||
|  | @ -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") | ||||
|  | @ -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"; | ||||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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…
	
	Add table
		
		Reference in a new issue
	
	 David Chavez
						David Chavez